home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / mailbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-14  |  92.7 KB  |  3,416 lines

  1. /* NOTE: because of size, the previous 'mailbox.c' has been
  2.  * split in 3 parts:
  3.  * mboxcmd.c, containing the 'mbox' subcommands, and
  4.  * mailbox.c, containing some user mailbox commands, and
  5.  * mailbox2.c, containing the remaining user commands.
  6.  * 921125 - WG7J
  7.  */
  8. /* There are only two functions in this mailbox code that depend on the
  9.  * underlying protocol, namely mbx_getname() and dochat(). All the other
  10.  * functions can hopefully be used without modification on other stream
  11.  * oriented protocols than AX.25 or NET/ROM.
  12.  *
  13.  * SM0RGV 890506, most work done previously by W9NK
  14.  *
  15.  *** Changed 900114 by KA9Q to use newline mapping features in stream socket
  16.  *    interface code; everything here uses C eol convention (\n)
  17.  *
  18.  *    Numerous new commands and other changes by SM0RGV, 900120
  19.  *
  20.  * Gateway function now support outgoing connects with the user's call
  21.  * with inverted ssid. Users can connect to system alias as well...
  22.  * See also several mods in socket.c,ax25.c and others
  23.  * 11/15/91, WG7J/PA3DIS
  24.  *
  25.  * Userlogging, RM,VM and KM commands, and R:-line interpretation
  26.  * added 920307 and later, Johan. K. Reinalda, WG7J/PA3DIS
  27.  *
  28.  * Inactivity timeout-disconnect added 920325 and later - WG7J
  29.  *
  30.  * Removed mbox overhead from calling Convers directly from ax25 - KO4KS
  31.  * Several other additions - KO4KS
  32.  */
  33. #include <stdio.h>
  34. #include <time.h>
  35. #include <io.h>
  36. #include <ctype.h>
  37. #include <alloc.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #ifdef  UNIX
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #endif
  44. #include <dir.h>
  45. #include <dos.h>
  46. #include "global.h"
  47. #include "config.h"
  48. #include "timer.h"
  49. #include "proc.h"
  50. #include "socket.h"
  51. #include "usock.h"
  52. #include "session.h"
  53. #include "smtp.h"
  54. #include "dirutil.h"
  55. #include "telnet.h"
  56. #include "ftp.h"
  57. #include "ftpserv.h"
  58. #include "commands.h"
  59. #include "netuser.h"
  60. #include "files.h"
  61. #include "bm.h"
  62. #include "pktdrvr.h"
  63. #include "ax25.h"
  64. #include "mailbox.h"
  65. #include "ax25mail.h"
  66. #include "nr4mail.h"
  67. #include "cmdparse.h"
  68. #include "mailfor.h"
  69. #include "help.h"
  70. #include "color.h"
  71.  
  72. #ifdef MAILBOX
  73.  
  74. /* Log all gateway connects to the logfile - WG7J */
  75. #define GWTRACE 1
  76.  
  77. /* By setting the fp to NULL, we can check in exitbbs()
  78.  * wether a tempfile has been closed or not - WG7J
  79.  */
  80. #define MYFCLOSE(x) { fclose(x); x = (FILE *) 0; }
  81.  
  82. /*
  83. #define MBDEBUG
  84. */
  85.  
  86. extern char *Mbhaddress;
  87. extern time_t StartTime;
  88. extern char Myalias[];
  89. extern int Mbfullsvc;
  90. extern char stars[];
  91. #ifdef TIPMAIL
  92. extern long Mbtipperms;
  93. #endif
  94. #ifdef WPAGES
  95. extern int MbWpages;
  96. #endif
  97. extern int Mbconverse;
  98. extern int FWDlzw;
  99. extern int MbLogging;
  100. extern int Smtpheaders;
  101.  
  102. struct mbx *Mbox[NUMMBX];
  103. int BbsUsers = 0;
  104. int Totallogins, Conflogins, Tutorlogins[3], BBSlogins;
  105. extern char *MMotd;
  106. extern char *MExit;
  107. extern char *Mtmsg;
  108. /* extern unsigned Maxlet; */
  109. extern int BBSdump;
  110. extern short SecureTelnet;
  111.  
  112. int MbSent = 0;
  113. int MbRead = 0;
  114. int MbRecvd = 0;
  115. #ifdef MBFWD
  116. int MbForwarded = 0;
  117. #endif
  118. static long lastsentid = 0;
  119.  
  120. extern char Noperm[];
  121. extern char Nosock[];
  122. extern char MboxId[], MboxIdFwd[];
  123. extern char *ANSIArea, *ANSILogin;
  124.  
  125. #ifdef ITT
  126. static char DFAR Loginbanner[] = "\n%s (%s)\n\n";
  127. #else
  128. static char DFAR Loginbanner[] = "\nKA9Q NOS - %s (%s)\n\n";
  129. #endif
  130. static char DFAR RLoginbanner[] = "\nRemote Login at %s - %s\n\n";
  131.  
  132. char DFAR Howtoend[] = "End with /EX or ^Z in first column (^A aborts):\n";
  133. static char DFAR CcLine[] = "Cc: ";
  134. static char DFAR Mbwelcome[] = "\nWelcome %s, ";
  135. static char DFAR Mbbanner[] = "to the %s TCP/IP Mailbox (%s)\n";
  136. static char DFAR Mbwarning[] = "Third Party mail is not permitted.\n";
  137. char DFAR CurUsers[] = "There are currently %d users on the BBS\n";
  138. char DFAR Only[] = "You are the only user currently on the BBS\n";
  139. static char DFAR MessageData[] = "%4d message%s - %4d new.\n";
  140. static char DFAR SMessageData[] = "%4d message%s - %4d new. (%4d on hold)\n";
  141. char DFAR MsgAborted[] = "*** Message aborted\n";
  142. static char DFAR sendthemail[] = "Send this message (N=no)?";
  143.  
  144. static char DFAR Mbmenu[] = "Current msg# %-d of %-d.\n?,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z ";
  145.  
  146. extern char Mbnrid[];
  147.  
  148. #ifdef nope
  149. #ifdef NETROM
  150. #ifdef CALLCLI
  151. static char Longmenu[] = "(?)help  (A)rea     (B)ye   (C)onnect (D)ownload (E)scape\n"
  152.                          "(F)inger (H)elp     (I)nfo  (J)heard  (K)ill     (L)ist   (M)boxusers\n"
  153.                          "(N)odes  (O)perator (P)orts (Q)uery   (R)ead     (S)end   (T)elnet\n"
  154.                          "(U)pload (V)erbose  (W)hat  (X)pert   (Z)ap\n";
  155. #else
  156. static char Longmenu[] = "(?)help    (A)rea  (B)ye    (C)onnect (D)ownload (E)scape    (F)inger\n"
  157.                          "(H)elp     (I)nfo  (J)heard (K)ill    (L)ist     (M)boxusers (N)odes\n"
  158.                          "(O)perator (P)orts (R)ead   (S)end    (T)elnet   (U)pload\n"
  159.                          "(V)erbose  (W)hat  (X)pert  (Z)ap\n";
  160. #endif /*CALLCLI*/
  161. #else /*NETROM*/
  162. #ifdef CALLCLI
  163. static char DFAR Longmenu[] = "(?)help (A)rea (B)ye    (C)onnect (CONF)erence (D)ownload  (E)scape   (F)inger\n"
  164.                   "(H)elp  (I)nfo (J)heard (K)ill    (L)ist       (M)boxusers (O)perator (P)orts\n"
  165.                               "(Q)uery (R)ead (S)end   (T)elnet  (U)pload     (V)erbose   (W)hat     (X)pert\n"
  166.                               "(Z)ap\n\n"
  167.                               "For further help, type 'help cmdname', where 'cmdname' is one of the above.\n\n";
  168. #else
  169. static char DFAR Longmenu[] = "(?)help (A)rea (B)ye    (C)onnect (CONF)erence (D)ownload  (E)scape   (F)inger\n"
  170.                   "(H)elp  (I)nfo (J)heard (K)ill    (L)ist       (M)boxusers (O)perator (P)orts\n"
  171.                               "(R)ead  (S)end (T)elnet (U)pload  (V)erbose    (W)hat      (X)pert    (Z)ap\n\n"
  172.                               "For further help, type 'help cmdname', where 'cmdname' is one of the above.\n\n";
  173. #endif /*CALLCLI*/
  174. #endif /*NETROM*/
  175. #endif /* nope */
  176.  
  177. extern int isgroup __ARGS((char *group));
  178. extern char *mblookname __ARGS((struct mbx *m,char *str));
  179. extern int dombusers __ARGS((int argc,char *argv[],void *p));
  180. extern int dombpast __ARGS((int argc,char *argv[],void *p));
  181. static int doarea __ARGS((int argc,char *argv[],void *p));
  182. extern int dombstatus __ARGS((int argc,char *argv[],void *p));
  183. static int dombcallbook __ARGS((int argc,char *argv[],void *p));
  184. void quickscan __ARGS((struct mbx *m, int olduser));
  185. extern void netPrompt __ARGS((void));
  186. extern int CountConfUsers __ARGS((void));
  187. extern char *getquote __ARGS((void));
  188. extern void tutorserv __ARGS((char *call, struct mbx *m, int mode, int color, int ip));
  189. extern char *skipwhite __ARGS((char *ptr));
  190. extern char *skipnonwhite __ARGS((char *ptr));
  191. extern void askhome __ARGS((struct mbx *m,int initial));
  192. extern int dosysop __ARGS((int argc,char *argv[],void *p));
  193. #ifdef LZW
  194. void togglelzw __ARGS((int soc, int mode));
  195. #endif
  196. extern char *cmd_line __ARGS((int argc,char *argv[],char stype));
  197. extern char *nntp_name_expansion __ARGS((char *name));
  198.  
  199. #ifdef WPAGES
  200. void wpageAdd __ARGS((char *entry, int bbs, int updateit));
  201. #endif
  202. extern char *host_or_wpage_exp __ARGS((char *to,int hier,int exphome));
  203. extern char *wpage_exp __ARGS((char *to,int hier,int exphome));
  204. extern FILE *subdir_fopen __ARGS((char *name, char *mode));
  205.  
  206. extern int Usenrid;
  207. extern int MBSecure;
  208. extern int Mbsendquery;
  209. #ifdef MBXTDISC
  210. extern int32 Mbtdiscinit;
  211. #endif
  212.  
  213. /*Enlighten them a bit!
  214.  */
  215. static void
  216. dombconnecthelp() {
  217. #ifdef NETROM
  218.     tputs("Syntax: 'C <node>'        for NET/ROM connects\n");
  219. #endif /* NETROM */
  220.     tputs("Syntax: 'C <port> <call>' for AX.25 connects\n\n");
  221. }
  222.  
  223. void
  224. bbscolorcls(m)
  225. struct mbx *m;
  226. {
  227.         if (m->usecolor)
  228.             colorcls ();
  229. }
  230.  
  231. void
  232. bbscolorchange (m, str)
  233. struct mbx *m;
  234. unsigned char *str;
  235. {
  236.         if (m->usecolor)
  237.             colorchange (str, m->colorset);
  238. }
  239.  
  240.  
  241. int
  242. dombports(argc,argv,p)
  243. int argc;
  244. char *argv[];
  245. void *p;
  246. {
  247. struct iface *ifp;
  248. struct mbx *m = (struct mbx *)p;
  249.     tputs("Available ports:\n");
  250.     for(ifp=Ifaces;ifp!=NULLIF;ifp=ifp->next)
  251.         if(ifp->type == CL_AX25 && \
  252.            (!(ifp->flags & HIDE_PORT) || (m->privs & SYSOP_CMD)) ) {
  253.             tprintf("%-7s",ifp->name);
  254.             if(ifp->descr != NULLCHAR)
  255.                 tprintf(":  %s",ifp->descr);
  256.             else
  257.                 tputc('\n');
  258.         }
  259.     tputc('\n');
  260.     return 0;
  261. }
  262.  
  263. /* This is called by the finger-daemon */
  264. void
  265. listusers(s)
  266. int s;
  267. {
  268. int outsave;
  269. struct mbx m;
  270.  
  271.     m.privs = 0;
  272.     m.stype = ' ';
  273.  
  274. #ifdef notdef
  275.     usprintf(s,"\nCurrent remote users:\n");
  276. #endif
  277.     outsave = Curproc->output;
  278.     Curproc->output = s;
  279.     dombusers(0,NULLCHARP,&m);
  280.     Curproc->output = outsave;
  281. }
  282.  
  283. struct mbx *
  284. newmbx()
  285. {
  286. int i;
  287. struct mbx *m;
  288.  
  289.     for(i = 0; i < NUMMBX; i++){
  290.         if(Mbox[i] == NULLMBX){
  291.             m = Mbox[i] = (struct mbx *)callocw(1,sizeof(struct mbx));
  292.             m->mbnum = i;
  293.             BbsUsers++;
  294.             return m;
  295.         }
  296.     }
  297.     /* If we get here, there are no free mailbox sessions */
  298.     return NULLMBX;
  299. }
  300.  
  301. static int
  302. mbx_getname(m)
  303. struct mbx *m;
  304. {
  305. char *cp;
  306. FILE *tfp;
  307. union sp sp;
  308. char tmp[MAXSOCKSIZE];
  309. int len = MAXSOCKSIZE;
  310. int anony = 0;
  311. int oldmode;
  312. int founddigit=0;
  313. int count=0;
  314.  
  315.     sp.p = tmp;
  316.     sp.sa->sa_family = AF_LOCAL;    /* default to AF_LOCAL */
  317.     getpeername(m->user,tmp,&len);
  318.     m->family = sp.sa->sa_family;
  319.     m->path = mallocw(MBXLINE);
  320.     /* This is one of the two parts of the mbox code that depends on the
  321.      * underlying protocol. We have to figure out the name of the
  322.      * calling station. This is only practical when AX.25 or NET/ROM is
  323.      * used. Telnet users have to identify themselves by a login procedure.
  324.      */
  325.     switch(sp.sa->sa_family){
  326. #ifdef    AX25
  327.     case AF_NETROM:
  328.     case AF_AX25:
  329.         /* NETROM and AX25 socket address structures are "compatible" */
  330.         /*Save user call, in case she/he wants to use gateway function*/
  331.         memcpy(m->call,sp.ax->ax25_addr,AXALEN);
  332.         m->call[ALEN] &= 0xfc;/*Make sure E-bit isn't set !*/
  333.         pax25(m->name,sp.ax->ax25_addr);
  334.         cp = strchr(m->name,'-');
  335.         if(cp != NULLCHAR)            /* get rid of SSID */
  336.             *cp = '\0';
  337.         /* SMTP wants the name to be in lower case */
  338.         strlwr (m->name);
  339.         anony = 1;
  340.         /* Try to find the privileges of this user from the userfile */
  341.         if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,&anony)) == -1){
  342.             m->privs = 0;
  343.             free(m->path);
  344.             m->path = NULLCHAR;
  345.         }
  346.         if(m->privs & EXCLUDED_CMD)
  347.             return -1;
  348.         return 0;
  349. #endif
  350.     case AF_LOCAL:
  351.     case AF_INET:
  352.         m->state = MBX_LOGIN;
  353.     if (m->type == RLOGIN_LINK)
  354.             tprintf(RLoginbanner,Hostname,Version);
  355.     else    {
  356.             tprintf(Loginbanner,Version,Hostname);
  357.             if(Mtmsg != NULLCHAR)
  358.                 tputs(Mtmsg);
  359.         }
  360.         for(;;){
  361.             /* Maximum of 3 tries - WG7J */
  362.             if(count++ == 3)
  363.                 return -1;
  364.             oldmode = sockmode(m->user,SOCK_ASCII);
  365.             tputs("login: ");
  366.             usflush(m->user);
  367.             if(mbxrecvline(m) == -1)
  368.                 return -1;
  369.             if(*m->line == 4) /* Control-d */
  370.                 return -1;
  371.             if(*m->line == '\0')
  372.                 continue;
  373.  
  374.             /* add a little test to avoid 'Mailfile busy' syndrome - WG7J */
  375.             if((cp=strchr(m->line,'.')) != NULLCHAR)
  376.                 *cp = '_';
  377.             if((cp=strchr(m->line,'/')) != NULLCHAR)
  378.                 *cp = '_';
  379.             if((cp=strchr(m->line,'\\')) != NULLCHAR)
  380.                 *cp = '_';
  381.             if((tfp=fopen(m->line,"w")) == NULL)  /* Invalid name */
  382.                 continue;
  383.             fclose(tfp);
  384.             unlink(m->line);
  385.             if(strlen(m->line) < sizeof(m->name))
  386.                 strcpy(m->name,m->line);
  387.             else    /* Too long! */
  388.                 continue;
  389.             tprintf("Password: %c%c%c",IAC,WILL,TN_ECHO);
  390.             usflush(m->user);
  391.             sockmode(m->user,SOCK_BINARY);
  392.             if(mbxrecvline(m) == -1)
  393.                 return -1;
  394.             tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  395.             sockmode(m->user,oldmode);
  396.             tputc('\n');
  397.             usflush(m->user);
  398.             /* This is needed if the password was send before the
  399.              * telnet no-echo options were receied. We neeed to
  400.              * flush the eold sequence from the input buffers, sigh
  401.              */
  402.             if(socklen(m->user,0))/* discard any remaining input */
  403.                 recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  404.             if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,&anony))
  405.              != -1){
  406.                 if(anony)
  407.                     log(m->user,"MBOX login: %s Password: %s",m->name,m->line);
  408.                 else
  409.                     log(m->user,"MBOX login: %s",m->name);
  410.                 if(m->privs & EXCLUDED_CMD)
  411.                     return -1;
  412. #ifdef TIPMAIL
  413.         if (anony && m->type == TIP)
  414.             m->privs = Mbtipperms;
  415. #endif
  416. #ifdef AX25
  417.                 /*try to set the name as the user-call.
  418.                  *this is a very crude test! Be careful...
  419.                  *Login must have at least 1 digit (0-9) in it,
  420.                  *and it must be possible to convert it to a call.
  421.                  *if this doesn't work, disallow the gateway command,
  422.                  *no matter if this was allowed by priviledges or not.
  423.                  *Be careful, some one with login name '4us' and
  424.                  *permission set to allow gateway/netrom, will
  425.                  *go out as '4us-15' or '4us-0' !!!!!
  426.                  *11/15/91 WG7J/PA3DIS
  427.                  */
  428.                 for(cp=m->name;*cp != '\0';cp++)
  429.                     if(isdigit((int)*cp))
  430.                         break;
  431.                 if(*cp != '\0')
  432.                     founddigit = 1;
  433.                 if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
  434.                     m->privs &= ~AX25_CMD;
  435.                     m->privs &= ~NETROM_CMD;
  436.                 }
  437. #else
  438.                 m->privs &= ~AX25_CMD;
  439.                 m->privs &= ~NETROM_CMD;
  440.  
  441. #endif /* AX25 */
  442.                 /* Set the morerows to MAXLIN for telnet logins - WG7J */
  443.                 m->morerows = MAXLIN - 1;
  444.                 return 0;
  445.             }
  446.             tputs("Login incorrect\n");
  447.             log(m->user,"MBOX login FAILED - login: %s Password: %s",m->name,m->line);
  448.         mail_error("MBOX Login failed: %s, pw %s",m->name,m->line);
  449.             *m->name = '\0';    /* wipe any garbage */
  450.         }
  451.     }
  452.     return 0;
  453. }
  454.  
  455. /* put up the prompt */
  456. void
  457. putprompt(m)
  458. struct mbx *m;
  459. {
  460. char area[64];
  461. char *cp1,*cp2;
  462. int inconf;
  463.  
  464.     if(m->sid & MBX_SID)
  465.         tputs(">\n");
  466.     else {
  467.         bbscolorchange (m, "09");
  468.         if(m->sid & MBX_NRID)
  469.             tputs(Mbnrid);
  470.         if(m->sid & MBX_AREA) {
  471.             cp1 = m->area;
  472.             cp2 = area;
  473.             /* Convert / and \ into . */
  474.             while(*cp1 != '\0') {
  475.                 if(*cp1=='/')
  476.                     *cp2 = '.';
  477.                 else
  478.                     *cp2 = *cp1;
  479.                 cp1++;
  480.                 cp2++;
  481.             }
  482.             *cp2 = '\0';
  483.             tprintf("Area: ");
  484.             bbscolorchange (m, "0C");
  485.             tprintf ("'%s' ", area);
  486.             bbscolorchange (m, "09");
  487.         if(m->privs & SYSOP_CMD)    {
  488. #ifdef CONVERS
  489.             inconf = CountConfUsers ();
  490. #else
  491.         inconf = 0;
  492. #endif
  493.         if((BbsUsers > 1) || inconf)    {
  494.             tputs ("(");
  495.             if (BbsUsers > 1)    {
  496.                     bbscolorchange (m, "0F");
  497.                 tprintf("%-d", BbsUsers);
  498.                     bbscolorchange (m, "09");
  499.                 tprintf(" users");
  500.             }
  501. #ifdef CONVERS
  502.             if ((BbsUsers > 1) && inconf)
  503.                 tputs (", ");
  504.             if (inconf)    {
  505.                     bbscolorchange (m, "0F");
  506.                 tprintf ("%-d", inconf);
  507.                     bbscolorchange (m, "09");
  508.                 tprintf (" in conference");
  509.             }
  510. #endif
  511.             tputs (") ");
  512.         }
  513.         }
  514.         }
  515.         bbscolorchange (m, "0B");        
  516.         tprintf((m->sid & MBX_EXPERT) ? (m->sid & MBX_AREA) ? "(%-d/%-d)" : "" : Mbmenu, m->current, m->nmsgs);
  517.         bbscolorchange (m, "0A");
  518.         tprintf (">\n");
  519.         bbscolorchange (m, "0E");
  520.     }
  521. }
  522.  
  523. #ifdef MBXTDISC
  524. /* Mailbox user has been idle for too long,
  525.  * disconnect the socket - WG7J
  526.  */
  527. void
  528. mboxredundant(m)
  529. struct mbx *m;
  530. {
  531. struct usock *up;
  532.  
  533. #ifdef notdef
  534.     /* After fix from Mark, ve3dte this is not needed anymore - WG7J */
  535.     /* nasty hack! we may have screwed up reference count */
  536.     /* by invoking newproc("smtp_send",....); Fudge it!   */
  537.     if((up = itop(m->user)) != NULLUSOCK)
  538.         up->refcnt = 1;
  539. #endif
  540.  
  541. /*    exitbbs (m);    */
  542.     /* Close the socket*/
  543.     close_s(m->user);
  544.     return; /* Keep lint happy */
  545. }
  546. #endif
  547.  
  548. extern void mbox_converse __ARGS((int, char *, int, struct mbx *));
  549.  
  550. /* Incoming mailbox session */
  551. void
  552. mbx_incom(s,t,p)
  553. int s;
  554. void *t;
  555. void *p;
  556. {
  557. struct tipcb *tip;
  558. struct mbx *m;
  559. struct usock *up;
  560. char *buf[3], *cp;
  561. char tmp[AXBUF];
  562. int rval;
  563. time_t newuser, loguser();
  564.  
  565.     sockmode(s,SOCK_ASCII);
  566.     sockowner(s,Curproc);    /* We own it now */
  567.     /* Secede from the parent's sockets, and use the network socket that
  568.      * was passed to us for both input and output. The reference
  569.      * count on this socket will still be 1; this allows the domboxbye()
  570.      * command to work by closing that socket with a single call.
  571.      * If we return, the socket will be closed automatically.
  572.      */
  573.     close_s(Curproc->output);
  574.     close_s(Curproc->input);
  575.     Curproc->output = Curproc->input = s;
  576.  
  577.     /* We'll do our own flushing right before we read input */
  578.     setflush(s,-1);
  579.  
  580.     if((m = newmbx()) == NULLMBX)    {
  581.             tputs("Too many mailbox sessions\n");
  582.         return;
  583.         }
  584.  
  585.     m->user = s;
  586.     m->escape = 20;        /* default escape character is Ctrl-T */
  587.     m->type = (int) t;
  588.     m->colorset[0] = 0;
  589. #ifdef TIPMAIL        
  590. #ifdef XMODEM
  591.     if (m->type==TIP) {
  592.         tip = (struct tipcb *) p;
  593.         tip->raw=0;
  594.         m->tip=tip;    
  595.     } 
  596. #endif        
  597. #endif
  598.  
  599. /* ??? */
  600.     while(socklen(s,0)) /* discard any remaining input */
  601.      recv_mbuf(s,NULL,0,NULLCHAR,0);
  602.     
  603.     
  604.     /* get the name of the remote station */
  605.     if(mbx_getname(m) == -1)    {
  606.         exitbbs(m);
  607.         return;
  608.         }
  609.     Totallogins++;
  610.     newuser = loguser(m);
  611.  
  612. #ifdef RLOGINSERV
  613.     if ((int)t == RLOGIN_LINK)    {
  614.         tputc ('\n');
  615.         dosysop (1, (char **)0, (void *)m);
  616.         exitbbs(m);
  617.         return;
  618.     }
  619. #endif
  620. #ifdef CONVERS
  621.     if((int)t != TIP && (int)t & CONF_LINK)    {
  622.         if(m->privs & NO_CONVERS)
  623.             tputs(Noperm);
  624.         else    {
  625.             m->state = MBX_CONVERS;
  626.             chname(Curproc,"conference");
  627.             log(s,"open CONF");
  628.             {
  629.                 int fd = m->user;
  630.                 char name[20];
  631.                 strcpy (name, m->name);
  632.                     Mbox[m->mbnum] = NULLMBX;
  633.                     free((char *)m);
  634.                     BbsUsers--;
  635.                 mbox_converse (fd, name, (int) -1, NULLMBX);
  636.             }
  637.         }
  638.             close_s(Curproc->output);
  639.             return;
  640.             }
  641. #endif
  642.  
  643. #ifdef TUTOR
  644.     if((int)t != TIP && ((int)t & TUTOR_LINK || (int)t & INFO_LINK || (int)t & NEWS_LINK))    {
  645.         m->state = MBX_TUTOR;
  646.         chname(Curproc,"tutorial");
  647.         log(s,"open TUTORIAL");
  648.         {
  649.             char name[20];
  650.             strcpy (name, m->name);
  651.                 Mbox[m->mbnum] = NULLMBX;
  652.                 free((char *)m);
  653.                 BbsUsers--;
  654. /*            setflush(s,'\n');  */     /* automatic flushing each line */
  655.             tutorserv (name, NULLMBX, ((int)t & INFO_LINK) ? 1 : ((int)t & NEWS_LINK) ? 2 : 0, m->usecolor, 0);
  656.             sleep (2);
  657.         }
  658.             close_s(Curproc->output);
  659.             return;
  660.             }
  661. #endif
  662.  
  663.     log(s,"open MBOX for '%s'", m->name);
  664.  
  665.     if (MbLogging)    {
  666.         char buf[128];
  667.         FILE *out;
  668.         sprintf(buf,"%s/mbox.log",Spool);
  669.         if((out = fopen(buf,APPEND_TEXT)) != NULLFILE)    {
  670.             time_t t;
  671.             time(&t);
  672.             fprintf (out, "MBOX from %s %s on %s", m->name, m->realname, ptime(&t));
  673.             fclose (out);
  674.         }
  675.     }
  676.  
  677.     BBSlogins++;
  678. #ifdef MBXTDISC
  679.     /*Start inactivity timer - WG7J */
  680.     set_timer(&m->tdisc,Mbtdiscinit * 1000L);
  681.     m->tdisc.func = mboxredundant;
  682.     m->tdisc.arg = m;
  683.     start_timer(&m->tdisc);
  684. #endif
  685.     if(m->privs & IS_BBS)
  686. /*        m->sid = MBX_SID; */ /*force bbs status*/
  687.         m->sid = MBX_EXPERT;    /* make BBS 'SID' itself, else it's sysop enters as EXPERT */
  688.     else if(m->privs & IS_EXPERT)
  689.         m->sid |= MBX_EXPERT;
  690.  
  691. /*    newuser = loguser(m);    */
  692. #ifdef LZW
  693.     if (m->sid & MBX_TNOS)    {
  694.         tputs ("Use LZW Compression (*y/n) ?\n");
  695.             if (mbxrecvline(m) != -1)    {
  696.             if (tolower (*m->line) != 'n')
  697.                 togglelzw (m->user, 1);
  698.             }
  699.         }
  700. #endif
  701.     m->state = MBX_CMD;    /* start in command state */
  702.     if (!(m->privs & IS_BBS) && (m->sid & MBX_GFX))
  703.         colorfile (ANSILogin, m->colorset);
  704.  
  705.     tputs(FWDlzw ? MboxIdFwd : MboxId);
  706.  
  707.     /* Say 'hello' only if user is not a bbs - WG7J */
  708. /*    if(!(m->sid & MBX_SID))    {    */
  709.     if(!(m->privs & IS_BBS))    {
  710.             bbscolorchange (m, "0F");
  711.         if (m->home[0] == '-')
  712.             askhome (m, 1);
  713.         if (m->realname == NULLCHAR)
  714.             askrealname (m, 1);
  715.         if(!(m->sid & MBX_RDMOTD))    {
  716.             DisplayFile (MOTDfile, s);
  717.             m->sid |= MBX_RDMOTD;
  718.             m->update = 1;
  719.             }
  720.         if (m->privs & SYSOP_CMD)
  721.             DisplayFile (MOTDsysfile, s);
  722.             tprintf(Mbwelcome,m->name);
  723. #ifdef AX25
  724.             if(m->family == AF_INET)
  725. #endif
  726.             tprintf(Mbbanner,Hostname,Version);
  727. #ifdef AX25
  728.         else
  729.             tprintf(Mbbanner,pax25(tmp,Mycall),Version);
  730. #endif
  731.         if (newuser > 0)
  732.             tprintf ("Last on the BBS: %s", ctime(&newuser));
  733.         if (BbsUsers == 1)
  734.             tprintf (Only);
  735.         else
  736.             tprintf(CurUsers,BbsUsers);
  737.         if(!ThirdParty || !Mbfullsvc)
  738.             tputs(Mbwarning);
  739.         if (!newuser)
  740.             DisplayFile (NEWUSERfile, s);
  741.         tflush ();
  742. #ifdef USERLOG
  743.         if (m->sid & MBX_STATS)
  744.             quickscan (m, (int) newuser);
  745. #endif
  746.         cp = getquote();
  747.         if (cp)        {
  748.             tprintf ("\nQuote of the Day:");
  749.                 bbscolorchange (m, "0A");
  750.             tprintf ("\n%s", cp);
  751.                 bbscolorchange (m, "0F");
  752.         }
  753.         if(((!cp) || strcmp (MMotd, cp)) && MMotd != NULLCHAR)
  754.             tprintf ("\n%s", MMotd);
  755.         free (cp);
  756.             usflush(m->user);
  757. #ifdef oldway
  758.             /* Enable our local message area,
  759.              * only if we're not a bbs - WG7J
  760.              */
  761.             buf[1] = m->name;
  762.             doarea(2,buf,m);
  763.         } else
  764.             m->mysize = 0;
  765. #else
  766.             m->special = ' ';
  767.         }
  768.            /* Enable our local message area */
  769.         buf[1] = m->name;
  770.            doarea(2,buf,m);
  771. #endif
  772.  
  773.     /* Send prompt */
  774.     if(!(m->privs & IS_BBS))
  775.         putprompt(m);
  776.     else    /* first prompt to a BBS has color disabled, after this it
  777.            depends on whether we have seen an SID. If an SID, no color.
  778.            This allows the BBS's SYSOP to 'live' login and have color
  779.            capabilities (after the first prompt).    */
  780.             tputs(">\n");
  781.  
  782.     while(mbxrecvline(m) != -1)    {
  783.         if (m->privs & EXCLUDED_CMD)
  784.             break;
  785.         if(m->special)    /* no-color BBS first prompt, also */
  786.             bbscolorchange (m, "0F");
  787.             if((rval = mbx_parse(m)) == -2)
  788.             break;
  789.         if(rval == 2)
  790.             break;
  791.         if (rval && BBSdump && (m->sid & MBX_SID))
  792.             break;
  793.         if (m->privs & EXCLUDED_CMD)
  794.             break;
  795.         if(rval == 1)
  796.             tputs("Bad syntax.\n");
  797.             notifynewmail (m);
  798.         /* Do not check mailfile if we're bbs, saves a tmpfile- WG7J*/
  799.         if(!(m->sid & MBX_SID))
  800.             scanmail(m);
  801.         putprompt(m);
  802.         m->state = MBX_CMD;
  803.         }
  804.     exitbbs(m);
  805.  
  806. #ifdef notdef
  807.     /* After fix from Mark, ve3dte this is not needed anymore - WG7J */
  808.     /* by invoking newproc("smtp_send",....); Fudge it!   */
  809.     if((up = itop(Curproc->output)) != NULLUSOCK)
  810.             up->refcnt = 1;
  811. #endif
  812.         usflush(Curproc->output);
  813.     mspause(500L);
  814.     close_s(Curproc->output);
  815. }
  816.  
  817. void
  818. exitbbs(m)
  819. struct mbx *m;
  820. {
  821. #ifdef MBXTDISC
  822.     stop_timer(&m->tdisc);
  823. #endif
  824.     closenotes(m);
  825.     free(m->to);
  826.     free(m->tofrom);
  827.     free(m->origto);
  828.     free(m->origbbs);
  829.     free(m->subject);
  830.     free(m->date);
  831.     free(m->tomsgid);
  832.     free(m->path);
  833.     free(m->home);
  834.     /* Close the tempfiles if they are not nullpointers - WG7J */
  835.     if(m->tfile != (FILE *) 0)
  836.             fclose(m->tfile);
  837.     if(m->tfp != (FILE *) 0)
  838.             fclose(m->tfp);
  839.     if(m->stdinbuf != NULLCHAR)
  840.         free(m->stdinbuf);
  841.     if(m->stdoutbuf != NULLCHAR)
  842.         free(m->stdoutbuf);
  843.     free((char *)m->mbox);
  844.     Mbox[m->mbnum] = NULLMBX;
  845.     free((char *)m);
  846.     if (BbsUsers)
  847.         BbsUsers--;
  848.     log(Curproc->output,"close MBOX from '%s'", m->name);
  849. }
  850.  
  851. /**********************************************************************/
  852.  
  853. int dochat __ARGS((int argc,char *argv[],void *p));
  854. static int dombconnect __ARGS((int argc,char *argv[],void *p));
  855. int dombconvers __ARGS((int argc,char *argv[],void *p));
  856. static int dombcall __ARGS((int argc,char *argv[],void *p));
  857. int dodownload __ARGS((int argc,char *argv[],void *p));
  858. int dombupload __ARGS((int argc,char *argv[],void *p));
  859. int dowhat __ARGS((int argc,char *argv[],void *p));
  860. int dozap __ARGS((int argc,char *argv[],void *p));
  861. int dosend __ARGS((int argc,char *argv[],void *p));
  862. static int dosid __ARGS((int argc,char *argv[],void *p));
  863. int dosysop __ARGS((int argc,char *argv[],void *p));
  864. int dostars __ARGS((int argc,char *argv[],void *p));
  865. int dombhelp __ARGS((int argc,char *argv[],void *p));
  866. int dombtelnet __ARGS((int argc,char *argv[],void *p));
  867. int dombfinger __ARGS((int argc,char *argv[],void *p));
  868. int dombquote __ARGS((int argc,char *argv[],void *p));
  869. int dombtutor __ARGS((int argc,char *argv[],void *p));
  870. int dombnews __ARGS((int argc,char *argv[],void *p));
  871. int dombexpert __ARGS((int argc,char *argv[],void *p));
  872. int dobump __ARGS((int argc,char *argv[],void *p));
  873. int dombfdesc __ARGS((int argc,char *argv[],void *p));
  874. int dombtime __ARGS((int argc,char *argv[],void *p));
  875. int dombwpages __ARGS((int argc,char *argv[],void *p));
  876. int dombset __ARGS((int argc,char *argv[],void *p));
  877. int dombget __ARGS((int argc,char *argv[],void *p));
  878. int dombrmail __ARGS((int argc,char *argv[],void *p));
  879. int dombgroup __ARGS((int argc,char *argv[],void *p));
  880. int doreply __ARGS((int argc,char *argv[],void *p));
  881. int douser __ARGS((int argc,char *argv[],void *p));
  882. int dombexpand __ARGS((int argc,char *argv[],void *p));
  883. int dombslip __ARGS((int argc,char *argv[],void *p));
  884. int dombjheard __ARGS((int argc,char *argv[],void *p));
  885. int dombiproute __ARGS((int argc,char *argv[],void *p));
  886. int dombroute __ARGS((int argc,char *argv[],void *p));
  887. extern int dobbshome __ARGS((int argc,char *argv[],void *p));
  888. static void gw_alarm __ARGS((void *p));
  889. static void gw_input __ARGS((int s,void *notused,void *p));
  890. static void gw_superv __ARGS((int null,void *proc,void *p));
  891. static int mbx_to __ARGS((int argc,char *argv[],void *p));
  892. int mbx_data __ARGS((struct mbx *m,struct list *cclist,char *extra, int returnreceipt));
  893. int msgidcheck __ARGS((char *string));
  894. static int thirdparty __ARGS((struct mbx *m));
  895. extern int doipheard __ARGS((int argc,char *argv[],void *p));
  896. extern int dorealname __ARGS((int argc,char *argv[],void *p));
  897. extern int doversion __ARGS((int argc,char *argv[],void *p));
  898. #ifdef NETROM
  899. static int dombnrnodes __ARGS((int argc,char *argv[],void *p));
  900. extern int donrneighbour __ARGS((int argc,char *argv[],void *p));
  901. #endif
  902.  
  903. struct cmds DFAR Mbcmds[] = {
  904.     "",        doreadnext,    0, 0, NULLCHAR,
  905.     "?",        dombhelp,    0, 0, NULLCHAR,
  906.     "Area",        doarea,        0, 0, NULLCHAR,
  907.     "Bye",        domboxbye,    0, 0, NULLCHAR,
  908.     "BUmp",         dobump,         0, 0, NULLCHAR,
  909.     "Connect",    dombconnect,    0, 0, NULLCHAR,
  910. #ifdef CALLBOOK
  911.     "CAll",        dombcall,    0, 0, NULLCHAR,
  912. #endif
  913. #ifdef SAMCALLB
  914.     "CAll",        dombcallbook,    0, 2, "Call callsign\nMultiple callsigns allowed per line",
  915. #endif
  916. #ifdef CONVERS
  917.     "CONFerence",    dombconvers,    0, 0, NULLCHAR,
  918. #endif
  919. #ifdef XMODEM
  920.     "Download",    dodownload,    0, 2, "D[U|X] filename",
  921. #else
  922.     "Download",    dodownload,     0, 2, "D[U] filename",
  923. #endif        
  924. /* next entry out of order DELIBERATELY, to make "D" download, not del! */
  925.     "DEl",        dozap,        0, 2, "DEL filename",
  926.     "DIr",          dowhat,         0, 0, NULLCHAR,
  927.     "Escape",    dombescape,    0, 0, NULLCHAR,
  928.     "EXit",        domboxbye,    0, 0, NULLCHAR,
  929.     "EXPand",    dombexpand,    0, 2, "EXPand aliasname",
  930.     "Finger",    dombfinger,    0, 0, NULLCHAR,
  931. /* next entry out of order DELIBERATELY, to make "F" finger, not fdesc! */
  932.     "FDesc",    dombfdesc,    0, 2, "FD filename",
  933.     "Get",        dombget,    0, 0, NULLCHAR,
  934.     "GRoup",    dombgroup,    0, 2, "GROUP action groupname",
  935.     "Help",        dombhelp,    0, 0, NULLCHAR,
  936.     "HOme",         dobbshome,    0, 0, NULLCHAR,
  937.     "Info",        dombhelp,    0, 0, NULLCHAR,
  938. /* next entry out of order DELIBERATELY, to make "I" info, not iheard! */
  939.     "IHeard",    doipheard,    0, 0, NULLCHAR,
  940.     "IProute",    dombiproute,    0, 0, NULLCHAR,
  941. #ifdef    AX25
  942.     "Jheard",    dombjheard,    0, 0, NULLCHAR,
  943. #endif
  944.     "Kill",        dodelmsg,    0, 0, NULLCHAR,
  945.     "List",        dolistnotes,    0, 0, NULLCHAR,
  946.     "Mboxusers",    dombusers,    0, 0, NULLCHAR,
  947.     "Name",         dorealname,    0, 0, NULLCHAR,
  948. #ifdef TUTOR
  949.     "NEws",         dombnews,      0, 0, NULLCHAR,
  950. #endif
  951. #ifdef NETROM
  952.     "NOdes",    dombnrnodes,    0, 0, NULLCHAR,
  953.     "NRoutes",    donrneighbour,    0, 0, NULLCHAR,
  954. #endif
  955.     "Operator",    dochat,        0, 0, NULLCHAR,
  956.     "Ping",        doping,        0, 0, NULLCHAR,
  957.     "POrts",    dombports,    0, 0, NULLCHAR,
  958.     "Quit",        domboxbye,    0, 0, NULLCHAR,
  959. /* next entry out of order DELIBERATELY, to make "Q" quit, not query! */
  960. #if defined(CALLCLI) || defined(SAMCALLB)
  961.     "QUEry",    dombcallbook,    0, 2, "Q callsign\nMultiple callsigns allowed per line",
  962. #endif
  963.     "QUOte",    dombquote,    0, 0, NULLCHAR,
  964.     "Read",        doreadmsg,    0, 0, NULLCHAR,
  965.     "REPly",    doreply,    0, 0, NULLCHAR,
  966. #ifdef RMAIL
  967.     "RMAil",    dombrmail,    0, 2, "RMAIL destbbs",
  968. #endif
  969.     "ROute",    dombroute,    0, 2, "ROute address",
  970.     "Send",        dosend,        0, 0, NULLCHAR,
  971.     "SET",        dombset,    0, 2, "SET A|C|F|M|N|S|SI|X",
  972. #ifdef TIPMAIL
  973.     "SLip",        dombslip,    0, 0, NULLCHAR,
  974. #endif
  975.     "Telnet",    dombtelnet,    0, 2, "T hostname",
  976.     "TIme",        dombtime,    0, 0, NULLCHAR,
  977. #ifdef TUTOR
  978.     "TUtor",        dombtutor,      0, 0, NULLCHAR,
  979. #endif
  980. #ifdef XMODEM        
  981.     "Upload",    dombupload,    0, 2, "U[X] filename",
  982. #else
  983.     "Upload",    dombupload,    0, 2, "U filename",
  984. #endif    
  985.     "USer",        douser,        0, 0, NULLCHAR,
  986.     "Verbose",    doreadmsg,    0, 0, NULLCHAR,
  987.     "VERSion",    doversion,    0, 0, NULLCHAR,
  988.     "What",        dowhat,        0, 0, NULLCHAR,
  989. #ifdef WPAGES
  990.     "WPages",    dombwpages,    0, 2, "WP call [@bbs]",
  991. #endif
  992.     "Xpert",    dombexpert,    0, 0, NULLCHAR,
  993.     "Zap",        dozap,        0, 2, "Z filename",
  994. /* the rest aren't displayed with "?" */
  995.     "[",        dosid,        0, 0, NULLCHAR,
  996.     "@",        dosysop,    0, 0, NULLCHAR,
  997. #ifdef    AX25
  998. #ifdef MBFWD
  999.     "f>",        dorevfwd,    0, 0, NULLCHAR,
  1000. #endif
  1001. #endif
  1002.     "***",        dostars,    0, 0, NULLCHAR,
  1003.     NULLCHAR,    NULLFP,        0, 0, "Huh?",
  1004. };
  1005.  
  1006. /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
  1007.  * They have to be treated specially since cmdparse() wants a space between
  1008.  * the actual command and its arguments.
  1009.  * "SP FOO" is converted to "s  foo" and the second command letter is saved
  1010.  * in m->stype. Longer commands like "SEND" are unaffected, except for
  1011.  * commands starting with "[", i.e. the SID, since we don't know what it will
  1012.  * look like.
  1013.  */
  1014. static char twocmds[] = "aslrd[mvkxwiu";    /* A,S,L,R,D,M,V,K,X,W,I,U are two-letter commands */
  1015.  
  1016. int
  1017. mbx_parse(m)
  1018. struct mbx *m;
  1019. {
  1020. char *cp, *cp2;
  1021. int i;
  1022. char *newargv[2];
  1023. unsigned char specialfound = 0;
  1024. int inbid = 0, sendtype = 0;
  1025.  
  1026.     /* Skip any spaces at the begining */
  1027.     for(cp = m->line;isspace(*cp);++cp)
  1028.         ;
  1029.     if (tolower (*cp) == 's')
  1030.         sendtype = 1;        /* a 'send' command, of some form */
  1031.  
  1032.     /* Translate entire buffer to lower case */
  1033.     /* fix by KO4KS to convert a message's BID to upper case.  */
  1034.     for (cp2 = cp; *cp2 != '\0'; ++cp2)    {
  1035.         if (sendtype && !inbid && *cp2 == '$')
  1036.             inbid = 1;
  1037.         if (!inbid)
  1038.             *cp2 = tolower(*cp2);
  1039.         else
  1040.             *cp2 = toupper(*cp2);
  1041.         if (*cp2 == ' ')
  1042.             inbid = 0;
  1043.     }
  1044.  
  1045.     m->special = m->stype = ' ';
  1046.     if (*cp == '^' || *cp == '~') {
  1047.         if (cp[1] == 's')    {
  1048.             m->special = *cp;
  1049.             specialfound = 0x80;
  1050.         }
  1051.         *cp++ = ' ';
  1052.     }
  1053.     if(*cp != '\0' && *(cp+1) != '\0')
  1054.         for(i=0; i<strlen(twocmds); ++i)    {
  1055.             if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
  1056.              || *cp == '['))    {
  1057.                 if(islower(*(++cp)))
  1058.                     m->stype = toupper(*cp); /* Save the second character */
  1059.                 else
  1060.                     m->stype = *cp;
  1061.                 m->stype |= specialfound;
  1062.                 *cp = ' ';
  1063.                 break;
  1064.             }
  1065.         }
  1066.     /* See if the input line consists solely of digits */
  1067.     cp = m->line;
  1068.     for(cp = m->line;isspace(*cp);++cp)
  1069.         ;
  1070.     if (*cp == ';')
  1071.         return 0;    /* allow self-identification */
  1072.     newargv[1] = cp;
  1073.     for(;*cp != '\0' && isdigit(*cp);++cp)
  1074.         ;
  1075.     if(*cp == '\0' && strlen(newargv[1]) > 0) {
  1076.             newargv[0] = "r";
  1077.             return doreadmsg(2,newargv,(void *)m);
  1078.     }
  1079.     return cmdparse(Mbcmds,m->line,(void *)m);
  1080. }
  1081.  
  1082. /* This works like recvline(), but telnet options are answered and the
  1083.  * terminating newline character is not put into the buffer. If the
  1084.  * incoming character equals the value of escape, any queued input is
  1085.  * flushed and -2 returned.
  1086.  */
  1087. int
  1088. mbxrecvline(m)
  1089. struct mbx *m;
  1090. {
  1091. int s = m->user;
  1092. int escape = m->escape;
  1093. char *buf = m->line;
  1094.     int c, cnt = 0, opt;
  1095.  
  1096.     if(buf == NULLCHAR)
  1097.         return 0;
  1098.     usflush(Curproc->output);
  1099. #ifdef MBXTDISC
  1100.     start_timer(&m->tdisc);
  1101. #endif
  1102.     while((c = recvchar(s)) != EOF){
  1103.         if(!m->inmessage && c == IAC){        /* Telnet command escape */
  1104.             if((c = recvchar(s)) == EOF)
  1105.                 break;
  1106.             if(c > 250 && c < 255 && (opt = recvchar(s)) != EOF){
  1107. #ifdef    foo
  1108.                 switch(c){
  1109.                 case WILL:
  1110.                     tprintf("%c%c%c",IAC,DONT,opt);
  1111.                     break;
  1112.                 case WONT:
  1113.                     tprintf("%c%c%c",IAC,DONT,opt);
  1114.                     break;
  1115.                 case DO:
  1116.                     tprintf("%c%c%c",IAC,WONT,opt);
  1117.                     break;
  1118.                 case DONT:
  1119.                     tprintf("%c%c%c",IAC,WONT,opt);
  1120.                 }
  1121. #endif
  1122. /* to be fixed             usflush(Curproc->output);*/
  1123.                 continue;
  1124.             }
  1125.             if(c != IAC && (c = recvchar(s)) == EOF)
  1126.                 break;
  1127.         }
  1128.         /* ordinary character */
  1129. #ifndef TNOS_68K
  1130.         if(c == '\r' || c == '\n')
  1131. #else
  1132.         if(c == '\r' || c == '\l')
  1133. #endif
  1134.             break;
  1135.         if(!m->inmessage && uchar(c) == escape){
  1136.             if(socklen(s,0)) /* discard any remaining input */
  1137.                 recv_mbuf(s,NULL,0,NULLCHAR,0);
  1138.             cnt = -2;
  1139.             break;
  1140.         }
  1141.         /* Handle <del> chars - from wa7tas */
  1142.         if(!m->inmessage && c == 8) {
  1143.             if(cnt > 0) {
  1144.                 *--buf = 0;
  1145.                 cnt--;
  1146.             }
  1147.         } else {
  1148.         *buf++ = c;
  1149.         ++cnt;
  1150.         }
  1151.             if(cnt == (MBXLINE - 1))    {
  1152.                 cnt = -2;
  1153.             break;
  1154.         }
  1155.     }
  1156.     if(c == EOF && cnt == 0)
  1157.         return -1;
  1158.     *buf = '\0';
  1159. #ifdef MBXTDISC
  1160.     /* Restart the timeout-timer - WG7J*/
  1161.     start_timer(&m->tdisc);
  1162. #endif
  1163.     return cnt;
  1164. }
  1165.  
  1166. extern void updatedefaults __ARGS((struct mbx *, int));
  1167.  
  1168. int
  1169. domboxbye(argc,argv,p)
  1170. int argc;
  1171. char *argv[];
  1172. void *p;
  1173. {
  1174. struct mbx *m;
  1175. long elapsedtime;
  1176. char *cptr;
  1177.  
  1178.     m = (struct mbx *)p;
  1179.  
  1180. #ifdef USERLOG
  1181.     if(!(m->sid & MBX_SID))        /* not a BBS */
  1182.         setlastread(m);
  1183.     if(m->update)
  1184.             updatedefaults(m, 0);
  1185. #endif
  1186.     if(m->sid & MBX_SID)        {    /* if a BBS */
  1187.         smtptick (NULL);    /* clean up any unfiled mail */
  1188.         mspause (500L);
  1189.         return -2;        /* for bbs's, just disconnect */
  1190.     }
  1191.  
  1192.     /* Now say goodbye */
  1193.     bbscolorchange (m, "09");
  1194.     tprintf("\nThank you ");
  1195.     bbscolorchange (m, "0C");
  1196.     tprintf (m->name);
  1197.     bbscolorchange (m, "09");
  1198. #ifdef ITT
  1199.     tprintf (", for calling the %s TMNG Tcp/Ip Mailbox.\n",    Hostname);
  1200. #else
  1201.     tprintf (", for calling the %s TNOS Tcp/Ip Mailbox.\n",    Hostname);
  1202. #endif
  1203.         time((time_t *)&elapsedtime);
  1204.         cptr = ctime((time_t *) &elapsedtime);
  1205.         rip (cptr);
  1206.         elapsedtime -= m->logontime;
  1207.         tprintf ("Logged off: ");
  1208.     bbscolorchange (m, "0F");
  1209.     tprintf (cptr);
  1210.     bbscolorchange (m, "09");
  1211.     tprintf (" --- Time this session: ");
  1212.     bbscolorchange (m, "0F");
  1213.     tprintf ("%s\n", tformat (elapsedtime));
  1214.     if(MExit != NULLCHAR)
  1215.         tprintf("%s\n",MExit);
  1216. #ifdef nope ALLSERV
  1217.     if(m->type == TIP)
  1218.             tputs("Please hang up now.\n");
  1219. #endif
  1220. /*    usflush(m->user);    */
  1221.     usflush(Curproc->output);
  1222.     return -2;    /* signal that exitbbs() should be called */
  1223. }
  1224.  
  1225. char *
  1226. addroot (root,name)
  1227. char *root, *name;
  1228. {
  1229.     return strdup (make_fname (root, name));
  1230. }
  1231.  
  1232.  
  1233. char *
  1234. permtest (path, privs, name, mode, root, dir)
  1235. char *path, *name, *root;
  1236. long privs;
  1237. int mode, dir;
  1238. {
  1239. char *file, *defdir, *cp;
  1240.  
  1241.     if (root == NULLCHAR)    {
  1242.         defdir = strdup(path);
  1243.         if ((cp = strchr (defdir, ';')) != NULLCHAR)
  1244.             *cp = 0;
  1245.     } else    defdir = strdup (root);
  1246.     if (dir)    
  1247.         file = strdup(defdir);
  1248.     else
  1249.         file = addroot (defdir, name);
  1250.     free (defdir);
  1251.     if(!permcheck(path,privs,mode,file))    {
  1252.         free (file);
  1253.         tputs(Noperm);
  1254.         return 0;
  1255.     }
  1256.     return file;
  1257. }
  1258.  
  1259.  
  1260. #if defined(CALLBOOK)
  1261. extern char *InetCallserver;
  1262. extern char *InetCallserverport;
  1263.  
  1264. /*This is a simple way of estiblishing a connection
  1265.  *to a callbook-server via tcp - WG7J
  1266.  */
  1267. static int
  1268. dombcall(argc,argv,p)
  1269. int argc;
  1270. char *argv[];
  1271. void *p;
  1272. {
  1273. char buf[8], *newargv[3];
  1274.  
  1275.     if(InetCallserver!=NULLCHAR){
  1276.         newargv[0] = "C";
  1277.         newargv[1] = InetCallserver;
  1278.         newargv[2] = InetCallserverport;
  1279.         SecureTelnet = 0;
  1280.         return dombtelnet(3,newargv,p);
  1281.     }
  1282.     else {
  1283.         tputs("Internet callserver not configured\n");
  1284.     }
  1285.     /* It returns only after a disconnect or refusal */
  1286.     return 0;
  1287. }
  1288.  
  1289. #endif /*CALLBOOK*/
  1290.  
  1291. #if defined(CALLCLI)  || defined(SAMCALLB)
  1292. static int
  1293. dombcallbook(argc,argv,p)
  1294. int argc;
  1295. char *argv[];
  1296. void *p;
  1297. {
  1298. struct mbx *m;
  1299. char buf[8], *newargv[3];
  1300. extern char *Callserver;
  1301. int req, ret = 0;
  1302.  
  1303.     if(argc > 2){
  1304.         tputs("Usage: Q callsign [callsign] [...]\n");
  1305.         return -1;
  1306.     }
  1307.     m = (struct mbx *) p;
  1308. #ifndef newcode
  1309.     sprintf(buf,"%d",IPPORT_CALLDB);
  1310.     newargv[0] = "C";
  1311. #else    /* to call KF5MG's callbook server, through FINGER */
  1312.     sprintf(buf,"%d",IPPORT_FINGER);
  1313.     newargv[0] = "t";
  1314. #endif
  1315.     newargv[1] = Callserver;
  1316.     newargv[2] = buf;
  1317.  
  1318.     for (req = 1; req < argc; req++)  {
  1319.         if (argv[req] == NULLCHAR) return ret;
  1320.         log(m->user, "%s checking callbook: %s",m->name,argv[req]);
  1321.         if (!Callserver || !*Callserver)    {
  1322. #ifdef SAMCALLB
  1323.             cb_lookup (Curproc->output, argv[req], (FILE *) 0);
  1324. #else
  1325.             cb_lookup (Curproc->output, argv[req]);
  1326. #endif
  1327.             ret = 0;
  1328.         } else    {
  1329.             m->startmsg = mallocw(80);  /* is freed each time by gw_connect() */
  1330.             sprintf(m->startmsg,"%s\n", argv[req]);
  1331.             tprintf("Looking for \"%s\" in the callbook at %s\n",argv[req],Callserver);
  1332.             SecureTelnet = 0;
  1333.             ret = dombtelnet(3,newargv,p);
  1334.         }
  1335.     }
  1336.     return ret; /* It looks like all possible returns are zero anyway!    */
  1337. }
  1338. #endif
  1339.  
  1340.  
  1341. extern int Mbloophold;
  1342.  
  1343. /*Some additional security - WG7J
  1344.  *NO_3PARTY =  disallow all 3rd party mail
  1345.  *NO_SENDCMD = only allow mail to sysop
  1346.  */
  1347. extern int NoBid;
  1348.  
  1349. int
  1350. dosend(argc,argv,p)
  1351. int argc;
  1352. char *argv[];
  1353. void *p;
  1354. {
  1355. int cccnt = 0, fail = 0;
  1356. char *host, *cp, *rhdr = NULLCHAR;
  1357. struct list *ap, *cclist = NULLLIST;
  1358. struct mbx *m;
  1359. FILE *fp;
  1360. time_t now;
  1361. int done = 0;
  1362. char *cp2;
  1363. char returnreceipt = 0, nosig = 0;
  1364. int foundCTLz = 0;
  1365. int c;
  1366. long here, datastart;
  1367.  
  1368. #ifdef RLINE
  1369. struct tm t;
  1370. #define ODLEN   16
  1371. #define OBLEN   32
  1372. char origdate[ODLEN];
  1373. char origbbs[OBLEN];
  1374. char fwdbbs[NUMFWDBBS][FWDBBSLEN+1];
  1375. int myfwds = 0;
  1376. register int i;
  1377. int zulu;
  1378. int check_r = 0, check_r2 = 0;
  1379. int found_r = 0, wrotedata = 0;
  1380. int loops = 0;
  1381. char Me[15];
  1382. int recvsize;
  1383. long messagesize;
  1384.  
  1385.     origdate[0] = '\0';
  1386.     origbbs[0] = '\0';
  1387. #endif
  1388.  
  1389.     m = (struct mbx *)p;
  1390.     if (m->stype & 0x80)    {
  1391.         if (m->special == '~')
  1392.             nosig = 1;
  1393.         else
  1394.             returnreceipt = 1;
  1395.         m->stype &= 0x7f;
  1396.     }
  1397.  
  1398. #ifdef TIPMAIL
  1399.     if(m->stype == 'L')
  1400.         return (dombslip (argc, argv, p));
  1401. #endif
  1402.     if((m->stype != 'R' || (m->sid & MBX_SID)) && mbx_to(argc,argv,m) == -1)    {
  1403.         tputs((m->sid & MBX_SID) ? "NO - syntax error\n" : \
  1404.                     "S command syntax error - format is:\nS[C|F] name [@ host] [< from_addr] [$bulletin_id]\nSR [number]\n");
  1405.         mail_error("%s: MBOX S syntax error - %s\n",m->name,cmd_line(argc,argv,m->stype));
  1406.         return 0;
  1407.     }
  1408.  
  1409.     bbscolorchange (m, "0D");
  1410.  
  1411.     /*Check for send permission */
  1412.     if(m->privs & NO_SENDCMD) { /*is this to 'SYSOP' or 'sysop' ?*/
  1413.         if(stricmp(m->to,"sysop"))     {
  1414.             tputs((m->sid & MBX_SID) ? "NO - permission denied\n" : \
  1415.                         "Sorry, only mail to 'sysop' allowed!\n");
  1416.             mail_error("%s: no mail permission - %s\n",m->name,m->to);
  1417.             return 0;
  1418.         }
  1419.     }
  1420.  
  1421.     /* Check for a BID on bulletins from other bbs's - WG7J */
  1422.     if((m->sid & MBX_SID) && !NoBid &&
  1423.         (m->stype == 'B') && (m->tomsgid == NULLCHAR)) {
  1424.         tputs("NO - No BID!\n");
  1425.         log(m->user,"MBOX %s: SB without BID - %s",m->name,m->to);
  1426.         mail_error("MBOX %s: SB without BID - %s",m->name,m->to);
  1427.         return 0;
  1428.     }
  1429.  
  1430.     pwait (NULL);        /* just to be nice to others */
  1431.     if(m->stype != 'R' && msgidcheck(m->tomsgid)) {
  1432.         if(m->sid & MBX_SID)
  1433.             tputs("NO - ");
  1434.         tprintf("Already have %s\n",m->tomsgid);
  1435.         return 0;
  1436.     }
  1437.  
  1438.     pwait (NULL);        /* just to be nice to others */
  1439. /*    if (!(m->sid & MBX_SID))    */    /* if BBS, no need! */
  1440.     if ((m->stype != 'B') && (m->stype != 'T') && (m->stype != 'R'))
  1441.         m->to = host_or_wpage_exp (m->to, 1, 0);
  1442.  
  1443.  
  1444. #ifdef WPAGES
  1445.     check_r2 = 1;
  1446. #endif
  1447.     if(m->stype == 'R' && !(m->sid & MBX_SID))
  1448.         if (mbx_reply(argc,argv,m,&cclist,&rhdr) == -1)
  1449.             return 0;
  1450.         else
  1451.             check_r2 = 0;
  1452.     if((cp = rewrite_address(m->to)) != NULLCHAR)
  1453.         if(stricmp(m->to,cp) != 0)    {
  1454.             m->origto = m->to;
  1455.             m->to = cp;
  1456.         } else
  1457.             free(cp);
  1458.  
  1459.     pwait (NULL);        /* just to be nice to others */
  1460.     /* refuse any mail that gets rewritten into 'refuse' - WG7J */
  1461.     if(!stricmp(m->to,"refuse"))     {
  1462.         tputs((m->sid & MBX_SID) ? "NO - refused\n" : \
  1463.                     "Bad user or hostname,  please mail 'sysop' for help\n");
  1464.         free (rhdr);
  1465.         return 0;
  1466.     }
  1467.  
  1468.     if( ((!Mbfullsvc || !ThirdParty) && !(m->privs & SYSOP_CMD)) || (m->privs & NO_3PARTY) )
  1469.         if(thirdparty(m) == 0)    {
  1470.             if (m->sid & MBX_SID)
  1471.                 tputs ("NO - ");
  1472.             tputs(Mbwarning);
  1473.         mail_error("%s: 3rd party mail refused - %s\n",m->name,m->to);
  1474.                 free (rhdr);
  1475.             return 0;
  1476.         }
  1477.  
  1478.     /* Send the new 'To:' line to sysops only - WG7J */
  1479.     if((m->privs&SYSOP_CMD) && (m->origto != NULLCHAR || m->stype == 'R') && !(m->sid & MBX_SID))
  1480.         tprintf("To: %s\n", m->to);
  1481.     if(validate_address(m->to) == 0)    {
  1482.         tputs((m->sid & MBX_SID) ? "NO - bad address\n" : \
  1483.                     "Bad user or hostname,  please mail 'sysop' for help\n");
  1484.         free(rhdr);
  1485.         del_list(cclist);
  1486.         /* We don't free any more buffers here. They are freed upon
  1487.          * the next call to mbx_to() or to domboxbye()     */
  1488.         return 0;
  1489.     }
  1490.     pwait (NULL);        /* just to be nice to others */
  1491.     /* Display the Cc: line (during SR command) */
  1492.     for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  1493.         if(cccnt == 0){
  1494.             tprintf("%s",Hdrs[CC]);
  1495.             cccnt = 4;
  1496.         } else {
  1497.             tputs(", ");
  1498.             cccnt += 2;
  1499.         }
  1500.         if(cccnt + strlen(ap->val) > 80 - 3) {
  1501.             tputs("\n    ");
  1502.             cccnt = 4;
  1503.         }
  1504.         tputs(ap->val);
  1505.         cccnt += strlen(ap->val);
  1506.     }
  1507.     if(cccnt)
  1508.         tputc('\n');
  1509.  
  1510.     pwait (NULL);        /* just to be nice to others */
  1511.     /* If the the command was 'SC' then read the Cc: list now - WG7J */
  1512.     if((m->stype == 'C') && !(m->sid & MBX_SID))     {
  1513.         m->stype = 'P'; /* make everything private */
  1514.         tputs(CcLine);
  1515.         if(mbxrecvline(m) != -1) {
  1516.             if(strlen(m->line))     {
  1517.                 if(*m->line == 0x01) { /* CTRL-A, abort */
  1518.                     free(rhdr);
  1519.                     del_list(cclist);
  1520.                     tputs(MsgAborted);
  1521.                     return 0;
  1522.                 }
  1523.                 cp = m->line;
  1524.                 /* get all the Cc addresses, separated by comma's */
  1525.                 while((cp2=strchr(cp,',')) != NULLCHAR)     {
  1526.                     *cp2 = '\0';
  1527.                     /*get rid of leading spaces or tabs*/
  1528.                     while(*cp == ' ' || *cp == '\t')
  1529.                         cp++;
  1530.                     if(strlen(cp))    {
  1531.                         cp = host_or_wpage_exp (strdup (cp), 0, 0);
  1532.                         addlist(&cclist,cp,0,cp);
  1533.                         free (cp);
  1534.                     }
  1535.                     cp = cp2 + 1;
  1536.                 }
  1537.                 /* Do the last or only one */
  1538.                 /* get rid of leading spaces or tabs*/
  1539.                 while(*cp == ' ' || *cp == '\t')
  1540.                     cp++;
  1541.                 if(strlen(cp))    {
  1542.                     cp = host_or_wpage_exp (strdup (cp), 0, 0);
  1543.                     addlist(&cclist,cp,0,cp);
  1544.                     free (cp);
  1545.                 }
  1546.             }
  1547.         } else {
  1548.             free(rhdr);
  1549.             del_list(cclist);
  1550.             return 0;
  1551.         }
  1552.     }
  1553.  
  1554.     /* Now check to make sure we can create the needed tempfiles - WG7J */
  1555.     if((m->tfile = tmpfile()) == NULLFILE) {
  1556.         free(rhdr);
  1557.         del_list(cclist);
  1558.         tputs((m->sid & MBX_SID) ? "NO - no temp file\n" : \
  1559.             "Can't create temp file for mail\n");
  1560.         return -2;    /* disconnect if no files!! */
  1561.     }
  1562. #ifdef RLINE
  1563.     pwait (NULL);        /* just to be nice to others */
  1564.     /* Only accept R: lines from bbs's */
  1565.     if((m->sid & MBX_SID)&&(Rdate || Rreturn || Rfwdcheck || Mbloophold)){
  1566.         /* Going to interpret R:headers, we need another tempfile !  */
  1567.         if((m->tfp = tmpfile()) == NULLFILE) {
  1568.             free(rhdr);
  1569.             del_list(cclist);
  1570.             tputs("NO - no temp file\n");
  1571.             return 0;
  1572.         }
  1573.         /* Now we got enough :-) */
  1574.         check_r = 1;
  1575.         Checklock++;
  1576.         /* Set the call, used in loop detect code - WG7J */
  1577.         if(Mbloophold) {
  1578.             pax25(Me,Mycall);
  1579.             if((cp = strchr(Me,'-')) != NULLCHAR)
  1580.                 *cp = '\0'; /* remove SSID */
  1581.         }
  1582.     }
  1583. #endif
  1584.  
  1585.     m->state = MBX_SUBJ;
  1586.     pwait (NULL);        /* just to be nice to others */
  1587.     if(m->stype != 'R' || (m->sid & MBX_SID))     {
  1588.         tputs((m->sid & MBX_SID) ? "OK\n" : "Subject:\n");
  1589.         if(mbxrecvline(m) == -1) {
  1590. #ifdef RLINE
  1591.             if(check_r) {
  1592.                 MYFCLOSE(m->tfp);
  1593.                 Checklock--;
  1594.             }
  1595. #endif
  1596.             free (rhdr);
  1597.             return 0;
  1598.         }
  1599.     } else                /* Replying to a message */
  1600.         tprintf("Subject: %s\n",m->line);
  1601.  
  1602.     m->subject = strdup(m->line);
  1603.  
  1604. #ifdef RLINE
  1605.     if(!check_r) {
  1606. #endif
  1607.         mbx_data(m,cclist,rhdr, returnreceipt);
  1608.         wrotedata = 1;
  1609. #ifdef RLINE
  1610.     }
  1611. #endif
  1612.     free(rhdr);
  1613.     m->state = MBX_DATA;
  1614.     pwait (NULL);        /* just to be nice to others */
  1615.  
  1616. #ifdef RMAIL
  1617.     if (m->change == -1)    {
  1618.         /* Write RMAIL line */
  1619.         fseek (m->tfile, -2, 1);
  1620.         for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  1621. #if 0
  1622.             if(cccnt == 0)    {
  1623.                 fprintf(m->tfile,"%s",Hdrs[TO]);
  1624.                 cccnt = 4;
  1625.                 cp2 = (m->origto) ? m->origto : m->to;
  1626.                 cp = strchr (cp2, '.');
  1627.                 i = (cp) ? (int)(cp - cp2) : strlen (cp2);
  1628.                 fwrite (cp2, 1, i, m->tfile);
  1629.                 cccnt += i;
  1630.             }
  1631. #endif
  1632.                 fprintf(m->tfile,", ");
  1633.                 cccnt += 2;
  1634.             fputs(ap->val,m->tfile);
  1635.             cccnt += strlen(ap->val);
  1636.             if (cccnt > 508)
  1637.                 break;
  1638.         }
  1639.         if(cccnt)
  1640.             fputs("\n\n",m->tfile);
  1641.         del_list(cclist);
  1642.         cclist = NULLLIST;
  1643.     }
  1644.     pwait (NULL);        /* just to be nice to others */
  1645. #endif
  1646.  
  1647.     if(!(m->sid & MBX_SID))        {
  1648.         if((m->privs&SYSOP_CMD) && (m->origto != NULLCHAR || m->stype == 'R') && !strcmp(m->to, "check"))
  1649.             tprintf("\007The system doesn't know where to route this message..\nSuggest you abort this message and re-enter!\n");
  1650.         tprintf("Enter %smessage%s%s",(m->stype == 'F') ? "a personal " : "",
  1651.             (m->stype == 'F') ? " to precede the forwarded message.\n" : ".  ", Howtoend);
  1652.     }
  1653.  
  1654.     bbscolorchange (m, "07");
  1655. #if 0    /* now in mbx_data() */
  1656.     /* Add a return receipt line, if requested */
  1657.     if (returnreceipt)    {
  1658.         fseek (m->tfile, -1, 1);
  1659.         fprintf(m->tfile, "%s%s@%s\n\n", Hdrs[RRECEIPT],m->name,Hostname);
  1660.         returnreceipt = 0;
  1661.     }
  1662. #endif
  1663.     datastart = ftell (m->tfile);
  1664.     m->inmessage = 1;
  1665.     if(Rfwdcheck) {        /* checking sender here JUST IN CASE R: line is bad or missing */
  1666.         for(i=0;i<Numfwds;i++) {
  1667.             if(!stricmp(MyFwds[i],m->name)) {
  1668.                 /*Found it !*/
  1669.                 strcpy(fwdbbs[myfwds++],m->name);
  1670.                 break;
  1671.             }
  1672.         }
  1673.     }
  1674.     while(!foundCTLz && ((recvsize = mbxrecvline(m)) != -1))     {
  1675.         pwait (NULL);        /* just in case sender is hosing us */
  1676.         if ((cp = strchr (m->line, CTLZ)) != NULLCHAR)    {
  1677.                 *(cp+1) = 0;
  1678.                 *cp = '\n';
  1679.             foundCTLz = 1;
  1680.             }
  1681.         if(m->line[0] == 0x01 || !strnicmp(m->line, "/a", 2))        {  /* CTRL-A */
  1682.                        MYFCLOSE(m->tfile);
  1683. #ifdef RLINE
  1684.             if(check_r)
  1685.                 MYFCLOSE(m->tfp);
  1686. #endif
  1687.             tputs(MsgAborted);
  1688.             del_list(cclist);
  1689.             return 0;
  1690.         }
  1691.         if(m->line[0] != CTLZ && strnicmp(m->line, "/e", 2) && strnicmp(m->line, "/b", 2) && strnicmp (m->line, "/q", 2) && strcmp (m->line, ".")) {
  1692.             if (*m->line == '/' && !(m->sid & MBX_SID))    {
  1693.                 cp = &m->line[2];
  1694.                 cp = skipnonwhite (cp);
  1695.                 cp = skipwhite (cp);
  1696.                 c = i = 0;
  1697.                 switch (tolower (m->line[1]))    {
  1698.                     case 'o':    i = 1;
  1699.                     case 'v':    if (m->stype != 'R')
  1700.                                 break;
  1701.                             if ((fp = tmpfile ()) != NULLFILE)    {
  1702.                                 tprintf ("%sOriginal message #%-d\n", stars, m->current);
  1703.                                 msgtofile(m, m->current, fp, i);
  1704.                                 rewind (fp);
  1705.                                 sendfile(fp, m->user, ASCII_TYPE,0);
  1706.                                 tprintf ("%s\n", stars);
  1707.                                 fclose (fp);
  1708.                             }
  1709.                             break;
  1710.                     case 'f':    if (!(cp = permtest(m->path, m->privs,cp,RETR_CMD, NULLCHAR, 0)))
  1711.                                 break;
  1712.                             if((fp = fopen(cp,READ_TEXT)) != NULLFILE)        {
  1713.                                 tprintf ("%sAdded file: %s\n", stars, cp);
  1714.                                 while(fgets(m->line,LINELEN,fp) != NULLCHAR)
  1715.                                     fputs(m->line,m->tfile);
  1716.                                 fclose(fp);
  1717.                             }
  1718.                             free (cp);
  1719.                             break;
  1720.                     case 'd':    if (*cp)
  1721.                                 i = atoi (cp);
  1722.                             if (!i)
  1723.                                 i = 1;
  1724.                             tprintf ("%sDeleted %d line%s\n", stars, i, (i - 1) ? "s" : "");
  1725.                             here = ftell (m->tfile);
  1726.                             while (here > 0)    {
  1727.                                 fseek (m->tfile, --here, SEEK_SET);
  1728.                                 if ((fgetc (m->tfile)) == '\n' && !(i--))
  1729.                                     break;
  1730.                                 fseek (m->tfile, here, SEEK_SET);
  1731.                                 putc ('\0', m->tfile);
  1732.                             }
  1733.                             break;
  1734.                     case '/':    strcpy (m->line, &m->line[1]);
  1735.                             c = 1;
  1736.                             break;
  1737.                     case 's':    nosig ^= 1;
  1738.                             tprintf ("%sSignature o%s\n", stars, nosig ? "ff" : "n");
  1739.                             break;
  1740.                     case 'p':    here = ftell (m->tfile);
  1741.                             fseek (m->tfile, datastart, SEEK_SET);
  1742.                             sendfile(m->tfile,m->user,ASCII_TYPE,0);
  1743.                             fseek (m->tfile, here, SEEK_SET);
  1744.                             tprintf ("%s\n", stars);
  1745.                             break;
  1746.                     case 'c':    if(strlen(cp))    {
  1747.                                 cp = host_or_wpage_exp (strdup (cp), 0, 0);
  1748.                                 addlist(&cclist,cp,0,cp);
  1749.                                 tprintf ("%sAdded call: %s\n", stars, cp);
  1750.                                 free (cp);
  1751.                             }
  1752.                             break;
  1753.                     case 'm':    i = atoi (cp);
  1754.                             if (i && i <= m->nmsgs)    {
  1755.                                 msgtofile(m,i,m->tfile,0);
  1756.                                 tprintf ("%sAdded Message: %d\n", stars, i);
  1757.                             }
  1758.                             break;
  1759.                     case 'h':
  1760.                     case '?':    bbscolorchange (m, "0B");
  1761.                             DisplayFile (EditorHelp, m->user);
  1762.                             bbscolorchange (m, "07");
  1763.                             break;
  1764.                 }
  1765.                 if (!c)
  1766.                     continue;
  1767.             }
  1768.  
  1769. #ifdef RLINE
  1770.             if(check_r || check_r2) {
  1771.                 pwait (NULL);        /* just to be nice to others */
  1772.                 /* Check for R: lines to start with */
  1773.                 /* Invalidate R: lines that don't have R:YYMMDD/ */
  1774.                 if((!strnicmp(m->line,"R:",2)) && (*(m->line+8) == '/')) {    /* found one */
  1775.                     found_r = 1;
  1776.                     /*Write this line to the second tempfile
  1777.                      *for later rewriting to the real one   */
  1778.                     fprintf(m->tfp,"%s\n",m->line);
  1779.                     /* Find the '@[:]CALL.STATE.COUNTRY'or
  1780.                      * or the '?[:]CALL.STATE.COUNTRY' string
  1781.                      * The : is optional.     */
  1782.                     if( ((cp=strchr(m->line,'@')) != NULLCHAR) || ((cp=strchr(m->line,'?')) != NULLCHAR) ) {
  1783.                         if((cp2=strpbrk(cp," \n\t")) != NULLCHAR)
  1784.                             *cp2 = '\0';
  1785.                         /* Some bbs's send @bbs instead of @:bbs*/
  1786.                         if (*++cp == ':')
  1787.                             cp++;
  1788. #ifdef nope    /* was WPAGES, now done in smtpserv */
  1789.                         if(MbWpages)
  1790.                             wpageAdd (cp, 1, 1);
  1791. #endif
  1792.                         pwait (NULL);        /* just to be nice to others */
  1793.                         /* if we use 'return addres' copy whole 'domain' name */
  1794.                         if(Rreturn)
  1795.                             if((strlen(cp) <= OBLEN) && (strlen(cp)))
  1796.                                 strcpy(origbbs,cp);
  1797.                         /* Optimize forwarding ? */
  1798.                         if(Rfwdcheck || Mbloophold) {
  1799.                             /*if there is a HADDRESS, cut off after '.'*/
  1800.                             if((cp2=strchr(cp,'.')) != NULLCHAR)
  1801.                                 *cp2 = '\0';
  1802.                             if(Mbloophold)
  1803.                                 /* check to see if this is my call ! */
  1804.                                 if(!stricmp(Me,cp))
  1805.                                     loops++;
  1806.                             /*cross-check with MyFwds list*/
  1807.                                             if(Rfwdcheck) {
  1808.                                 for(i=0;i<Numfwds;i++) {
  1809.                                     if(!stricmp(MyFwds[i],cp)) {
  1810.                                         /*Found one !*/
  1811.                                         strcpy(fwdbbs[myfwds++],cp);
  1812.                                         break;
  1813.                                     }
  1814.                                 }
  1815.                             }
  1816.                         }
  1817.                     }
  1818.                     if(Rdate) {
  1819.                         /* Find the 'R:yymmdd/hhmmz' string */
  1820.                         if((cp=strchr(m->line,' ')) != NULLCHAR) {
  1821.                             *cp = '\0';
  1822.                             if(strlen(m->line+2) <= ODLEN)
  1823.                                 strcpy(origdate,m->line+2);
  1824.                         }
  1825.                     }
  1826.                 } else {    /* if not R: line */
  1827.                     /* The previous line was last R: line
  1828.                      * so we're done checking
  1829.                      * now write the smtp headers and
  1830.                      * all saved R: lines to the right tempfile    */
  1831.                     if (check_r)    {
  1832.                         check_r = 0;
  1833.                                     Checklock--;
  1834.                                     if (Checklock < 0)
  1835.                                            Checklock = 0;
  1836.                     }
  1837.                     check_r2 = 0;
  1838.                     /*Did we actually find one ?*/
  1839.                     if(found_r) {
  1840.                         if(Rreturn)
  1841.                             m->origbbs = strdup(strlwr(origbbs));
  1842.                         if(Rdate) {
  1843.                             if((cp=strchr(origdate,'/')) != NULLCHAR) {
  1844.                                 if((*(cp+5) == 'z') || (*(cp+5) == 'Z')) {
  1845.                                     *(cp+5) = '\0';
  1846.                                     zulu = 1;
  1847.                                 }
  1848.                                 t.tm_min = atoi(cp+3);
  1849.                                 *(cp+3) = '\0';
  1850.                                 t.tm_hour = atoi(cp+1);
  1851.                                 *cp = '\0';
  1852.                                 t.tm_mday = atoi(&origdate[4]);
  1853.                                 origdate[4] = '\0';
  1854.                                 t.tm_mon = (atoi(&origdate[2]) - 1);
  1855.                                 origdate[2] = '\0';
  1856.                                 t.tm_year = atoi(origdate);
  1857.                                 /* Set the date in rfc 822 format */
  1858.                                 m->date = mallocw(40);
  1859.                                 sprintf(m->date,"%.2d %s %02d %02d:%02d:00 %.3s\n",
  1860.                                     t.tm_mday, Months[t.tm_mon], t.tm_year, t.tm_hour, t.tm_min, zulu ? "UTC" : "");
  1861.                             }
  1862.                         }
  1863.                     }
  1864.                     /* Now write the headers,
  1865.                      * possibly adding Xforwarded lines for bulletins,
  1866.                      * or anything that has a BID.
  1867.                      * Add the X-Forwarded lines FIRST,
  1868.                      * this speeds up forwarding...  */
  1869.                     if(Mbloophold && loops >= Mbloophold)
  1870.                         fprintf(m->tfile,"%sLoop\n",Hdrs[XBBSHOLD]);
  1871.                     if(Rfwdcheck && found_r && ((m->stype == 'B') || (m->tomsgid)) )    {
  1872.                         /*write Xforwarded headers*/
  1873.                         for(i=0;i<myfwds;i++)
  1874.                             fprintf(m->tfile,"%s%s\n",Hdrs[XFORWARD],fwdbbs[i]);
  1875.                     }
  1876.                     /*write regular headers*/
  1877.                     if (!wrotedata)    {
  1878.                         mbx_data(m,cclist,NULLCHAR, returnreceipt);
  1879.                         wrotedata = 1;
  1880.                     }
  1881.                     pwait (NULL);        /* just to be nice to others */
  1882.  
  1883.                     /* Now copy the R: lines back */
  1884.                     if(found_r) {
  1885.                         char tmpline[MBXLINE];
  1886.                         rewind(m->tfp);
  1887.                         while(fgets(tmpline,sizeof(tmpline),m->tfp)!=NULLCHAR)    {
  1888.                             pwait (NULL);        /* just to be nice to others */
  1889.                             fputs(tmpline,m->tfile);
  1890.                         }
  1891.                     }
  1892.                     MYFCLOSE(m->tfp);
  1893.                         /* And add this first non-R: line */
  1894.                     fprintf(m->tfile,"%s\n",m->line);
  1895.                 }
  1896.             } else        {    /* not check_r or check_r2 */
  1897. #endif
  1898.                 fprintf(m->tfile,"%s",m->line);
  1899.                 if (recvsize != - 2)
  1900.                     putc ('\n', m->tfile);
  1901.             }
  1902.         } else {    /* CTLZ or /ex */
  1903. #ifdef RLINE
  1904.             if(check_r) {
  1905.                 /* Hmm, this means we never finished the R: headers
  1906.                  * tmp file still open !         */
  1907.                 MYFCLOSE(m->tfp);
  1908.             }
  1909. #endif
  1910.             done = 1; /* To indicate the difference between
  1911.                                       * mbxrecvline() returning -1 and /ex ! - WG7J
  1912.                                       * Now also used to indicate if the message should
  1913.                                       * be sent or not !    */
  1914.             /* Now ask users if they want to send this ! - WG7J */
  1915.             if( Mbsendquery && !(m->sid & MBX_SID)) {
  1916.                 if(m->type == TELNET || m->type == TIP)
  1917.                     c = tkeywait(sendthemail,0);
  1918.                 else  /* For AX.25 and NET/ROM connects */
  1919.                     c = mykeywait(sendthemail,m);
  1920.                 if(c == -1 || c == 'n' || c == 'N') {
  1921.                     done = 0;   /* signal delete of message */
  1922.                     tputs(MsgAborted);
  1923.                 }
  1924.             }
  1925.             break;  /* all done */
  1926.         }
  1927.     }
  1928.         if(!done && !foundCTLz) {
  1929.         /* We did NOT get ^Z or /EX, but mbxrecvline returned -1 !!!
  1930.          * This means the connection is gone ! - WG7J    */
  1931.         MYFCLOSE(m->tfile);
  1932. #ifdef RLINE
  1933.         if(check_r)
  1934.             MYFCLOSE(m->tfp);
  1935. #endif
  1936.         del_list(cclist);
  1937. /*                 free(rhdr); */    /*Just in case*/
  1938.         return 0;
  1939.     }
  1940.     m->inmessage = 0;
  1941.     if (m->stype == 'F') {    /* type == 'F' */
  1942.         tputs ("Inserting original message...\n");
  1943.         usflush(m->user);
  1944.         fprintf(m->tfile,"----- Forwarded message -----\n\n");
  1945.         msgtofile(m,m->current,m->tfile,0);
  1946.         fprintf(m->tfile,"----- End of forwarded message -----\n");
  1947.     }
  1948.  
  1949.     /* Insert customized signature if one is found */
  1950.     if(!nosig && !(m->sid & MBX_SID)) {    /* not a forwarding BBS */
  1951.         char sigwork[LINELEN];
  1952.         sprintf(sigwork,"%s/%s.sig",Signature,m->tofrom ? m->tofrom : m->name);
  1953.         if((fp = fopen(sigwork,READ_TEXT)) != NULLFILE)        {
  1954.             while(fgets(sigwork,LINELEN,fp) != NULLCHAR)    {
  1955.                 pwait (NULL);        /* just to be nice to others */
  1956.                 fputs(sigwork,m->tfile);
  1957.             }
  1958.             fclose(fp);
  1959.         }
  1960.     }
  1961.  
  1962.     if((host = strrchr(m->to,'@')) == NULLCHAR) {
  1963.         host = Hostname;    /* use our hostname */
  1964.         if(m->origto != NULLCHAR) {
  1965.             /* rewrite_address() will be called again by our
  1966.              * SMTP server, so revert to the original address.
  1967.              */
  1968.              free(m->to);
  1969.             m->to = m->origto;
  1970.             m->origto = NULLCHAR;
  1971.         }
  1972.     } else
  1973.         host++;    /* use the host part of address */
  1974.  
  1975.     {
  1976.     char fullfrom[MBXLINE];
  1977.  
  1978.         /* make up full from name for work file */
  1979.         if(m->tofrom != NULLCHAR)
  1980.             sprintf(fullfrom,"%s%%%s@%s",m->tofrom, m->name, Hostname);
  1981.         else
  1982.             sprintf(fullfrom,"%s@%s",m->name,Hostname);
  1983.         if(cclist != NULLLIST && stricmp(host,Hostname) != 0) {
  1984.             fseek(m->tfile,0L,0);    /* reset to beginning */
  1985.             pwait (NULL);        /* just to be nice to others */
  1986.             fail = queuejob(m->tfile,Hostname,cclist,fullfrom);
  1987.             del_list(cclist);
  1988.             cclist = NULLLIST;
  1989.         }
  1990.         addlist(&cclist,m->to,0,m->to);
  1991.         fseek(m->tfile,0L,0);
  1992.         pwait (NULL);        /* just to be nice to others */
  1993.         fail += queuejob(m->tfile,host,cclist,fullfrom);
  1994.     }
  1995.     del_list(cclist);
  1996.     messagesize = filelength (fileno(m->tfile));
  1997.     MYFCLOSE(m->tfile);
  1998.     if(fail)    {
  1999.         if(!(m->sid & MBX_SID)) /* only when we're not a bbs */
  2000.             tputs("Couldn't queue message for delivery\n");
  2001.     } else {
  2002.         if(!(m->sid & MBX_SID)) /* only when we're not a bbs */
  2003.             tputs("Message queued\n");
  2004.         if(m->sid & MBX_SID)
  2005.             MbRecvd++;
  2006.         else    {
  2007.             MbSent++;
  2008.             if (MbHolding && m->stype == 'B')
  2009.                 tputs("Bulletins are held till reviewed by the SYSOP\n");
  2010.         }
  2011. #ifdef notdef
  2012.         /* BID is now saved in the smtp server ! - WG7J */
  2013.         time(&now);
  2014.         if(m->tomsgid != NULLCHAR && (fp = fopen(Historyfile,APPEND_TEXT)) != NULLFILE) {
  2015.             fprintf(fp,"%s %ld\n",m->tomsgid,now); /* Save BID in history file */
  2016.             fclose(fp);
  2017.         }
  2018. #endif
  2019.         pwait (NULL);        /* just to be nice to others */
  2020.     }
  2021.     if (m->sid & MBX_SID)     {
  2022.         m->mysize = ((m->mysize + 1) % 10);
  2023.         if (!m->mysize)
  2024.             smtptick(NULL);        /* wake SMTP to send that mail */
  2025.     } else        {
  2026.         char buf[50], *cp;
  2027.         sprintf (buf, "%s", Hostname);
  2028.         if((cp = strchr(buf,'.')) != NULLCHAR)
  2029.             *cp = '\0';
  2030.         strupr(buf);
  2031.         tprintf ("\n*** Message forwarding to: %s\n*** MID: ", m->to);
  2032.         if (m->tomsgid)
  2033.             tprintf (m->tomsgid);
  2034.         else
  2035.             tprintf ("%ld_%s", lastsentid, buf);
  2036.         tprintf ("    Size: %ld\n\n", messagesize);
  2037.         /* Instead of kicking off the smtp now, let it happen in a short time.
  2038.          * That way the user gets the prompt back immediately, and the smtp kick
  2039.          * will run when the user most likely is working on typing the next command.
  2040.          * this *should* improve the user's perception of system's speed, and
  2041.          * might speed up bbs forwarding a bit too... :-) - WG7J
  2042.          */
  2043.         {
  2044.         #define WAITTM 5000L
  2045.             extern struct timer Smtpcli_t;
  2046.             long t;
  2047.             int32 old;
  2048.  
  2049.                 stop_timer(&Smtpcli_t);
  2050.                 t = read_timer(&Smtpcli_t);
  2051.                 old = Smtpcli_t.duration;
  2052.                 if(t <= 0  || t > WAITTM)
  2053.                      set_timer(&Smtpcli_t,WAITTM);  /* set timer duration */
  2054.                 if(Smtpcli_t.func == NULL) {    /* in case not set yet */
  2055.                     Smtpcli_t.func = (void (*)__ARGS((void*)))smtptick;/* what to call on timeout */
  2056.                     Smtpcli_t.arg = NULL;       /* dummy value */
  2057.                 }
  2058.                 start_timer(&Smtpcli_t);        /* and fire it up */
  2059.                 Smtpcli_t.duration = old;
  2060.         }
  2061. #ifdef nope
  2062.         smtptick(NULL);     /* wake SMTP to send that mail */
  2063. #endif
  2064.     }
  2065.     pwait (NULL);
  2066.     return 0;
  2067. }
  2068.  
  2069. #ifdef NETROM
  2070. static int
  2071. dombnrnodes(argc,argv,p)
  2072. int argc;
  2073. char *argv[];
  2074. void *p;
  2075. {
  2076. struct mbx *m;
  2077.  
  2078.     m = (struct mbx *)p;
  2079.  
  2080.     if(argc < 2)
  2081.         return doroutedump();
  2082.     if(*argv[1] == '*')
  2083.         argc = 1;
  2084.     return dorouteinfo(argc,argv,p);
  2085. }
  2086. #endif
  2087.  
  2088. static int
  2089. dosid(argc,argv,p)
  2090. int argc;
  2091. char *argv[];
  2092. void *p;
  2093. {
  2094. struct mbx *m;
  2095. char *cp, *flags;
  2096. struct usock *up;
  2097.  
  2098.     m = (struct mbx *)p;
  2099.     if(argc == 1)
  2100.         return 1;
  2101.     if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
  2102.         return 1;
  2103.     m->usecolor = 0;
  2104. #ifdef notdef
  2105.     if(m->stype == 'Z' && strnicmp(argv[1],"cz",2) == 0) {
  2106.         /* LAN-LINK's [ZCZ] */
  2107.         m->sid |= MBX_LL;
  2108.         return 0;
  2109.     }
  2110. #endif
  2111.     /* Other bbs's */
  2112.     m->sid = MBX_SID;
  2113.  
  2114.     /* Now check to see if this is an RLI board.
  2115.      * As usual, Hank does it a bit differently from
  2116.      * the rest of the world.
  2117.      */
  2118.     if(m->stype == 'R' && strnicmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
  2119.         m->sid |= MBX_RLI_SID;
  2120.     /* Check to see if the BBS supports a kludge called "hierarchical
  2121.      * routing designators."
  2122.      *
  2123.      * No need to check for ']' -- it must be there or this is not
  2124.      * a valid mbox id -- it is checked earlier (fix de OH3LKU)
  2125.      *
  2126.      * Sid format is [BBSTYPE-VERSION-OPTIONS]
  2127.      * check for LAST -, to allow for version portion. - WG7J
  2128.      */
  2129.     flags = strrchr(argv[1], '-');
  2130.     if(flags != NULLCHAR && (cp=strchr(flags+1,'h')) != NULLCHAR && strchr(cp+1,'$'))
  2131.         m->sid |= MBX_HIER_SID;
  2132. #ifdef LZW
  2133.     /* Check to see if it's another TNOS board */
  2134.     if (flags != NULLCHAR && (cp=strchr(flags+1, 't')) != NULLCHAR)    {
  2135.         if (m->state != MBX_FORWARD)    {    /* if forwarding, wait till we can send out SSID */
  2136.             up = itop(m->user);
  2137.             if(up->zout == NULLLZW)
  2138.                     togglelzw (m->user, 1);
  2139.         }
  2140.             m->sid |= MBX_TNOS;
  2141.     }
  2142. #endif
  2143.     if (flags != NULLCHAR && (cp=strchr (flags+1, 'm')) != NULLCHAR)
  2144.         m->sid |= MBX_MID;
  2145.     if (flags != NULLCHAR && (cp=strchr (flags+1, 'f')) != NULLCHAR)    {
  2146.         m->sid |= MBX_FBB;
  2147.         if ((cp = strchr (flags+1, 'b')) != NULLCHAR)
  2148.             m->sid |= MBX_FBBCOMP;
  2149.     }
  2150.     m->mysize = 0;
  2151.     return 0;
  2152. }
  2153.  
  2154.  
  2155. int
  2156. dombescape(argc,argv,p)
  2157. int argc;
  2158. char *argv[];
  2159. void *p;
  2160. {
  2161. struct mbx *m;
  2162.  
  2163.     m = (struct mbx *)p;
  2164.     if(argc < 2)    {
  2165.             tprintf("Escape is %s, Escape char: ", (m->privs & NO_ESCAPE) ? "OFF" : "ON");
  2166.         if(m->escape < 32)
  2167.             tprintf("CTRL-%c\n",m->escape+'A'-1);
  2168.         else
  2169.             tprintf("'%c'\n",m->escape);
  2170.         return 0;
  2171.     }
  2172.     if(strlen(argv[1]) > 1) {
  2173.         if(isdigit(*argv[1]))
  2174.             m->escape = (char) atoi(argv[1]);
  2175.         else {
  2176.             if( !strnicmp(argv[1],"OFF",3) || !strnicmp(argv[1],"dis",3) )
  2177.                 m->privs |= NO_ESCAPE;
  2178.             else
  2179.                 m->privs &= ~NO_ESCAPE;
  2180.         }
  2181.     } else
  2182.         m->escape = *argv[1];
  2183.     return 0;
  2184. }
  2185.  
  2186. /* Routine for finding out total number of messages for an area and the
  2187.    number of messages that are new to this user. Just reports NEW messages,
  2188.    does not check their read status (for personal areas). Though it USES the
  2189.    mbox structure, it returns it back to the previous state. This routine
  2190.    reads the area.ctl files, which just contain a bid for each message.  */
  2191.  
  2192. static void
  2193. statarea(m, area, total, new, hold, special)
  2194. register struct mbx *m;
  2195. char *area;
  2196. int *total, *new, *hold, special;
  2197. {
  2198. long last, newlast, num;
  2199. char oldarea[20], buf[256];
  2200. FILE *fp;
  2201. long size;
  2202. struct let *lt;
  2203. register struct    let *cmsg;
  2204. register int i;
  2205. register int tnew, ttotal, thold;
  2206.  
  2207.     ttotal = tnew = thold = 0;
  2208. #ifdef USERLOG
  2209.     last = m->lastread;
  2210.     newlast = m->newlastread;
  2211.     m->lastread = 0;
  2212.     strcpy (oldarea, m->area);
  2213.     strcpy (m->area, area);
  2214.     if (!lockit (m))        {
  2215.         /* only read last read message-id if this is not a bbs,
  2216.          * current area is a public area and not 'help'
  2217.          * or area starts with 'sys'
  2218.          * read in all cases if a SYSOP
  2219.          */
  2220.  
  2221.         if(!(m->sid & MBX_SID))
  2222.             if( (stricmp(area,"help") && isarea(area)) || !strnicmp(m->area,"sys",3) || (m->privs & SYSOP_CMD))
  2223.                 getlastread(m);
  2224.         pwait (NULL);
  2225.         sprintf (buf, "%s/CONTROL/%s", Mailspool, m->area);
  2226.         nntp_name_expansion (buf);
  2227.         strcat (buf, ".ctl");
  2228.         if ((fp = subdir_fopen (buf, READ_BINARY)) != NULLFILE)    {
  2229.             size = filelength (fileno(fp));
  2230.             lt = (struct let *) malloc (size);
  2231.             fread (lt, size, 1, fp);
  2232.             fclose(fp);
  2233.             ttotal = (int) (size / (long) sizeof(struct let));
  2234.             pwait(NULL);
  2235.             for (cmsg = lt,i = 0; i < ttotal; i++, cmsg++)
  2236.                 if (!special)    {
  2237.                     if ((cmsg->bid > m->lastread) && !(cmsg->status & BM_DELETE))
  2238.                         tnew += 1;
  2239.                     if (cmsg->status & BM_ONHOLD)
  2240.                         thold += 1;
  2241.                 } else    {
  2242.                     if (!(cmsg->status & BM_READ))
  2243.                         tnew += 1;
  2244.                 }
  2245.             free (lt);
  2246.             }
  2247.         pwait (NULL);
  2248.         m->lastread = last;
  2249.         m->newlastread = newlast;
  2250.         rmlock (Mailspool, m->area);
  2251.         strcpy (m->area, oldarea);
  2252.         }
  2253. #endif
  2254.     *new = tnew;
  2255.     *total = ttotal;
  2256.     *hold = thold;
  2257. }
  2258.  
  2259.  
  2260. static int
  2261. doarea(argc,argv,p)
  2262. int argc;
  2263. char *argv[];
  2264. void *p;
  2265. {
  2266. struct mbx *m;
  2267. char *cp, *area, *tmparea, *theone;
  2268. FILE *fp;
  2269. char buf[MBXLINE];
  2270. int k;
  2271. int hold, total, new, xtotal = 0, xnew = 0;
  2272. struct no_mf *nm;
  2273. struct ffblk ff;
  2274.  
  2275.     m = (struct mbx *) p;
  2276.     if ((m->stype == 'F') && m->usecolor && !access (ANSIArea, 0))    {
  2277.         colorfile (ANSIArea, m->colorset);
  2278.         return 0;
  2279.     }
  2280.     if(argc < 2 || m->stype == 'N' || m->stype == 'S')        {
  2281.         area = strdup(m->area);
  2282.         tmparea = strdup(m->area);
  2283.         while((cp = strchr(tmparea,'/')) != NULLCHAR)
  2284.             *cp = '.';
  2285.         bbscolorcls (m);
  2286.         tprintf("Current message area is: %s\n\n",tmparea);
  2287.         free (tmparea);
  2288.  
  2289.         bbscolorchange (m, "0B");
  2290.         tputs("Available areas are:\n");
  2291.         total = m->nmsgs;
  2292.         new = m->newmsgs;
  2293.         if (stricmp (m->area, m->name))        {
  2294.             changearea(m,m->name, (int) 1);
  2295.         }
  2296.         else
  2297.             scanmail (m);
  2298.         if ((m->stype == 'N' && m->newmsgs) || m->stype != 'N')    {
  2299.             bbscolorchange (m, "09");
  2300.             tprintf ("%-15s  ",m->name);
  2301.         }
  2302.         if(m->stype == 'F')
  2303.             tputs("  Your private mail area\n");
  2304.         else if ((m->stype == 'S') || (m->stype == 'N' && m->newmsgs))    {
  2305.             bbscolorchange (m, "07");
  2306.             tprintf(MessageData, m->nmsgs,
  2307.                 m->nmsgs == 1 ? " " : "s", m->newmsgs);
  2308. /*            tprintf(MessageData, total,total == 1 ? " " : "s", new); */
  2309.             xtotal += total;
  2310.             xnew += new;
  2311.         }
  2312.         else if (m->stype != 'N')
  2313.             tputc('\n');
  2314.         theone = Arealist;
  2315.         if((m->privs & SYSOP_CMD) && (!access(AreaSlist, 0)))
  2316.             theone = AreaSlist;
  2317.         if((fp = fopen(theone,READ_TEXT)) == NULLFILE)
  2318.             return 0;
  2319.         if(m->stype == 'F')    {
  2320.             sendfile(fp,m->user,ASCII_TYPE,0);
  2321.             tputc('\n');
  2322.             }
  2323.         else if (m->stype == 'S' || m->stype == 'N')    {
  2324.             while(fgets(buf,MBXLINE,fp) != NULLCHAR)     {
  2325.                 pwait(NULL);
  2326.                 if(isalnum(buf[0]))     { /* skip comments */
  2327.                     if((cp=strpbrk(buf," \t")) != NULLCHAR)
  2328.                         *cp = '\0';
  2329.                     statarea (m, buf, &total, &new, &hold, 0);
  2330.                     if (m->stype == 'S' || new)    {
  2331.                         bbscolorchange (m, "09");
  2332.                         tprintf ("%-15.15s  ", buf);
  2333.                         bbscolorchange (m, "07");
  2334.                         if ((m->privs & SYSOP_CMD) && hold)
  2335.                             tprintf(SMessageData, total,
  2336.                                 total == 1 ? " " : "s", new, hold);
  2337.                         else
  2338.                             tprintf(MessageData, total,
  2339.                                 total == 1 ? " " : "s", new);
  2340.                         usflush(Curproc->output);
  2341.                         xtotal += total;
  2342.                         xnew += new;
  2343.                         }
  2344.                     }
  2345.                 }
  2346.             if ((m->privs & SYSOP_CMD) && argv[1][0] == 'a')    {    /* also list mailfor's if 'AN|S all' */
  2347.                 sprintf(buf,"%s/*.txt",Mailspool);
  2348.                 if (findfirst(buf, &ff, 0) == 0)    {
  2349.                     do    {
  2350.                         pwait(NULL);    /* Let others run */
  2351.                         *(strchr(ff.ff_name,'.')) = '\0';
  2352.                         /*must be private mail area, and not on exclude list !*/
  2353.                         if(!issysarea(ff.ff_name)) {
  2354.                             if (!stricmp (ff.ff_name, m->name))
  2355.                                 continue;
  2356.                             statarea (m, ff.ff_name, &total, &new, &hold, 1);
  2357.                             if (m->stype == 'S' || new)    {
  2358.                                 bbscolorchange (m, "09");
  2359.                                 tprintf ("%-15.15s  ", ff.ff_name);
  2360.                                 bbscolorchange (m, "07");
  2361.                                 tprintf(MessageData, total,
  2362.                                     total == 1 ? " " : "s", new);
  2363.                                 usflush(Curproc->output);
  2364.                                 xtotal += total;
  2365.                                 xnew += new;
  2366.                                 }
  2367.                         }
  2368.                     } while (findnext(&ff) == 0);
  2369.                 }
  2370.             }
  2371.             bbscolorchange (m, "0B");
  2372.             tputs("*** Total ***    ");
  2373.             tprintf(MessageData, xtotal,xtotal == 1 ? " " : "s", xnew);
  2374.             usflush(Curproc->output);
  2375.             tputc('\n');
  2376.             }
  2377.         else         {
  2378.             /* send only the area names, not the description */
  2379.             k = 0;
  2380.             while(fgets(buf,MBXLINE,fp) != NULLCHAR)     {
  2381.                 if(isalnum(buf[0]))     { /* skip comments */
  2382.                     if((cp=strpbrk(buf," \t")) != NULLCHAR)
  2383.                         *cp = '\0';
  2384.                     tprintf ("%-15.15s", buf);
  2385.                     if (++k == 5)    {
  2386.                         tputc('\n');
  2387.                         k = 0;
  2388.                         }
  2389.                     }
  2390.                 }
  2391.             if (k)
  2392.                 tputc('\n');
  2393.             bbscolorchange (m, "0A");            
  2394.             tputs("\nType AF to get description of areas\n\n");
  2395.             }
  2396.         if (stricmp (area, m->area))
  2397.             changearea(m,area, (int) 0);            
  2398.         free(area);
  2399.         fclose(fp);
  2400.         return 0;
  2401.         }
  2402.     if((m->privs & SYSOP_CMD) || stricmp(m->name,argv[1]) == 0){
  2403.         /*Private mail-areas*/
  2404.         changearea(m,argv[1], (int) 1);
  2405.         if(m->nmsgs && !(m->privs&IS_BBS)){
  2406.             if(!stricmp(m->name,m->area))
  2407.                         tputs("You have ");
  2408.             else {
  2409.                 area = strdup(m->area);
  2410.                 while((cp = strchr(area,'/')) != NULLCHAR)
  2411.                     *cp = '.';
  2412.                 tprintf("%s: ",area);
  2413.                 free(area);
  2414.             }
  2415.             tprintf((m->hmsgs) ? SMessageData : MessageData, m->nmsgs,
  2416.               m->nmsgs == 1 ? " " : "s", m->newmsgs, m->hmsgs);
  2417.         }
  2418.         if (m->stype == 'L')    {
  2419.             m->stype = ' ';
  2420.             dolistnotes (0, 0, m);
  2421.         }
  2422.         return 0;
  2423.     }
  2424.     if(isarea(argv[1])) {
  2425.         /*Public mail areas*/
  2426.         changearea(m,argv[1], (int) 1);
  2427.         area = strdup(m->area);
  2428.         while((cp = strchr(area,'/')) != NULLCHAR)
  2429.             *cp = '.';
  2430.         if (!(m->privs & IS_BBS))
  2431. #ifdef USERLOG
  2432.             tprintf("%s: %d message%s -  %d new\n",area,m->nmsgs,
  2433.                 m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  2434. #else
  2435.                 tprintf("%s: %d message%s.\n", area, m->nmsgs,
  2436.                     m->nmsgs == 1 ? "" : "s");
  2437. #endif
  2438.             free(area);
  2439.         if (m->stype == 'L')    {
  2440.             m->stype = ' ';
  2441.             dolistnotes (0, 0, m);
  2442.         }
  2443.     }
  2444.     else
  2445.         tprintf("No such message area: %s\n",argv[1]);
  2446.     return 0;
  2447. }
  2448.  
  2449. char *
  2450. nntp_name_expansion (name)
  2451. char *name;
  2452. {
  2453. char *cp;
  2454.  
  2455.     while((cp = strpbrk(name,".\\")) != NULLCHAR)
  2456.         *cp = '/';
  2457.     return name;
  2458. }
  2459.  
  2460.  
  2461. /* subroutine to do the actual switch from one area to another */
  2462. /* USERLOGGING added by WG7J */
  2463. void
  2464. changearea(m,area,setit)
  2465. struct mbx *m;
  2466. char *area;
  2467. int setit;
  2468. {
  2469. char *cp;
  2470.  
  2471. #ifdef USERLOG
  2472.     if (setit)
  2473.          setlastread(m);
  2474. #endif
  2475.     closenotes(m);
  2476.     m->nmsgs = m->newmsgs = m->current = 0;
  2477.     strcpy(m->area,area);
  2478.     nntp_name_expansion (m->area);
  2479.  
  2480. #ifdef USERLOG
  2481.     /* only read last read message-id if this is not a bbs,
  2482.      * current area is a public area and not 'help'
  2483.      * or area starts with 'sys'
  2484.      * read in all cases if a SYSOP
  2485.      */
  2486.     if(!(m->sid & MBX_SID))
  2487.         if( (stricmp(area,"help") && isarea(area)) || !strnicmp(m->area,"sys",3) || (m->privs & SYSOP_CMD))
  2488.             getlastread(m);
  2489. #endif
  2490.     scanmail(m);
  2491. }
  2492.  
  2493. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  2494.  * when the connection has been established unless it a null pointer.
  2495.  */
  2496. int
  2497. gw_connect(m,s,fsocket,len)
  2498. struct mbx *m;
  2499. int s;
  2500. struct sockaddr *fsocket;
  2501. int len;
  2502. {
  2503. int c;
  2504. char *cp, *cp1;
  2505. struct proc *child;
  2506. struct gwalarm *gwa;
  2507. char *node, *tocall, whereto[128], buf[80];
  2508. char temp[AXBUF];
  2509. struct nrroute_tab *rp;
  2510.  
  2511.     sockmode(s,SOCK_ASCII);
  2512.     child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
  2513.     tputs("Trying...");
  2514.     if(m->privs & NO_ESCAPE)
  2515.         tputc('\n');
  2516.     else {
  2517.         tputs("  The escape character is: ");
  2518.         if(m->escape < 32)
  2519.             tprintf("CTRL-%c\n",m->escape+'A'-1);
  2520.         else
  2521.             tprintf("'%c'\n",m->escape);
  2522.     }
  2523.     usflush(Curproc->output);
  2524.  
  2525.     /*find out where we're going to*/
  2526.     tocall = strdup(psocket(fsocket));
  2527.     if((cp1 = strchr(tocall,' ')) != NULLCHAR)
  2528.         *cp1 = '\0';
  2529. #ifdef NETROM
  2530.     if(fsocket->sa_family == AF_NETROM) {
  2531.         /*find the node alias*/
  2532.         setcall(temp,tocall);
  2533.         rp = find_nrroute(temp);
  2534.         node = strdup(rp->alias);
  2535.         if((cp1 = strchr(node,' ')) != NULLCHAR)
  2536.                     *cp1 = '\0';
  2537.         sprintf(whereto,"%s:%s",node,tocall);
  2538.         free(node);
  2539.     } else
  2540. #endif
  2541.      strcpy(whereto,tocall);
  2542.     free(tocall);
  2543.  
  2544.     if(connect(s,(char *)fsocket,len) == -1){
  2545.         if((cp = sockerr(s)) != NULLCHAR) {
  2546.             switch(cp[0]) {
  2547.             case 'R':
  2548.                 sprintf(buf,"%susy from",
  2549.                     (m->family == AF_NETROM)?"B":"*** b");
  2550.                 break;
  2551.             case 'T':
  2552.                 if(m->family != AF_NETROM) {
  2553.                     sprintf(buf,"*** timeout with");
  2554.                     break;
  2555.                 }
  2556.             default:
  2557.                 sprintf(buf,"%sailure with",
  2558.                     (m->family == AF_NETROM)?"F":"*** f");
  2559.                 break;
  2560.             }
  2561.             tprintf("%s%s %s\n\n",
  2562.                 (m->family == AF_NETROM) ? Mbnrid : "",buf,whereto);
  2563.         }
  2564.         shutdown(s,2);  /* HB9RWM suggestion */
  2565.         close_s(s);
  2566.         killproc(child);
  2567.         /* Free m->starmsg if set ! - WG7J */
  2568.         if(m->startmsg != NULLCHAR) {
  2569.             free(m->startmsg);
  2570.             m->startmsg = NULLCHAR;
  2571.         }
  2572.  
  2573.         return 0;
  2574.     }
  2575.     /* The user did not type the escape character */
  2576.     killproc(child);
  2577.  
  2578.     tprintf("%s%sonnected to %s\n",
  2579.         (m->family == AF_NETROM) ? Mbnrid : "",
  2580.         (m->family == AF_NETROM) ? "C" : "*** c",
  2581.         whereto);
  2582.  
  2583.     if(m->startmsg != NULLCHAR){
  2584.         usputs(s,m->startmsg);
  2585.         free(m->startmsg);
  2586.         m->startmsg = NULLCHAR;
  2587.     }
  2588.  
  2589.     /* Since NOS does not flush the output socket after a certain
  2590.      * period of time, we have to arrange that ourselves.
  2591.      */
  2592.     gwa = (struct gwalarm *) mallocw(sizeof(struct gwalarm));
  2593.     gwa->s1 = Curproc->output;
  2594.     gwa->s2 = s;
  2595.     set_timer(&gwa->t,2*1000L);
  2596.     gwa->t.func = gw_alarm;
  2597.     gwa->t.arg = (void *) gwa;
  2598.     start_timer(&gwa->t);
  2599.     /* Fork off the receive process */
  2600.     child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
  2601.  
  2602.     for(;;){
  2603.         if((c = recvchar(Curproc->input)) == EOF)
  2604.             break;
  2605.         /* Only check ESCAPE char if that is currently turned on */
  2606.         if( !(m->privs & NO_ESCAPE) && c == m->escape){
  2607.             if(socklen(Curproc->input,0))
  2608.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  2609.             break;
  2610.         }
  2611. #ifdef MBXTDISC
  2612.         if(c == '\n')
  2613.             start_timer(&m->tdisc);
  2614. #endif
  2615.         if(usputc(s,c) == EOF)
  2616.             break;
  2617.     }
  2618.     stop_timer(&gwa->t);
  2619.     free((char *)gwa);
  2620.     close_s(s);
  2621.     killproc(child); /* get rid of the receive process */
  2622.     if(m->family == AF_INET)
  2623.         tprintf("%c%c%c\n",IAC,WONT,TN_ECHO);
  2624.     return 0;
  2625. }
  2626.  
  2627. static void
  2628. gw_input(s,notused,p)
  2629. int s;
  2630. void *notused;
  2631. void *p;
  2632. {
  2633. int c;
  2634. struct proc *parent;
  2635. struct mbx *m;
  2636. char *cp, *cp1;
  2637. char response[4];
  2638.  
  2639.     parent = (struct proc *) p;
  2640.     m = (struct mbx *) notused;
  2641.  
  2642.     cp1 = strdup(Mbnrid);
  2643.     if((cp = strchr(cp1,'}')) != NULLCHAR)
  2644.         *cp = '\0';
  2645.     strupr(cp1);
  2646.  
  2647. #ifdef notdef
  2648.     while((c = recvchar(s)) != EOF)
  2649.         tputc(c);
  2650. #endif
  2651.     while((c = recvchar(s)) != EOF){
  2652.         if(c != IAC){
  2653.             tputc((char)c);
  2654.             continue;
  2655.         }
  2656.         /* IAC received, get command sequence */
  2657.         c = recvchar(s);
  2658.         switch(c){
  2659.         case WILL:
  2660.             response[0] = IAC;
  2661.             response[1] = DONT;
  2662.             response[2] = recvchar(s);
  2663.             response[3] = '\0';
  2664.             usputs(s,response);
  2665.             break;
  2666.         case WONT:
  2667.         case DONT:
  2668.             c = recvchar(s);
  2669.             break;
  2670.         case DO:
  2671.             response[0] = IAC;
  2672.             response[1] = WONT;
  2673.             response[2] = recvchar(s);
  2674.             response[3] = '\0';
  2675.             usputs(s,response);
  2676.             break;
  2677.         case IAC:    /* Escaped IAC */
  2678.             usputc(s,IAC);
  2679.             break;
  2680.         }
  2681.     }
  2682.  
  2683.     if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
  2684.         switch(cp[0]) {
  2685.         case 'T':
  2686.             usprintf(m->user,"\n*** %s: Link failure",cp1);
  2687.             break;
  2688.         case 'R':
  2689.             usprintf(m->user,"*** DM received");
  2690.             break;
  2691.         }
  2692.     }
  2693.     usprintf(m->user,"\n%s%seconnected to %s\n\n",
  2694.         (m->family == AF_NETROM) ? Mbnrid : "",
  2695.         (m->family == AF_NETROM) ? "R" : "*** r",
  2696.         cp1);
  2697.  
  2698.     free(cp1);
  2699.     cp1 = NULLCHAR;
  2700.  
  2701.     /* Tell the parent that we are no longer connected */
  2702.     alert(parent,ENOTCONN);
  2703.     pwait(Curproc); /* Now wait to be killed */
  2704. }
  2705.  
  2706. /* Check if the escape character is typed while the parent process is busy
  2707.  * doing other things. 
  2708.  */
  2709. static void
  2710. gw_superv(null,proc,p)
  2711. int null;
  2712. void *proc;
  2713. void *p;
  2714. {
  2715. struct proc *parent;
  2716. struct mbx *m;
  2717. int c;
  2718.  
  2719.     parent = (struct proc *) proc;
  2720.     m = (struct mbx *) p;
  2721.     while((c = recvchar(Curproc->input)) != EOF)
  2722.         if(c == m->escape){
  2723.             /* flush anything in the input queue */
  2724.             if(socklen(Curproc->input,0))
  2725.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  2726.             break;
  2727.         }
  2728.     alert(parent,EINTR);     /* Tell the parent to quit */
  2729.     pwait(Curproc);         /* Please kill me */
  2730. }
  2731.  
  2732. static void
  2733. gw_alarm(p)
  2734. void *p;
  2735. {
  2736. struct gwalarm *gwa = (struct gwalarm *)p;
  2737. char oldbl;
  2738. struct usock *up;
  2739.  
  2740.     /* Flush sockets s1 and s2, but first make sure that the socket
  2741.      * is set to non-blocking mode, to prevent the flush from blocking
  2742.      * if the high water mark has been reached.
  2743.      */
  2744.     if((up = itop(gwa->s1)) != NULLUSOCK) {
  2745.         oldbl = up->noblock;
  2746.         up->noblock = 1;
  2747.         usflush(gwa->s1);
  2748.         up->noblock = oldbl;
  2749.     }
  2750.     if((up = itop(gwa->s2)) != NULLUSOCK) {
  2751.         oldbl = up->noblock;
  2752.         up->noblock = 1;
  2753.         usflush(gwa->s2);
  2754.         up->noblock = oldbl;
  2755.     }
  2756.     start_timer(&gwa->t);
  2757. }
  2758.  
  2759. /* States for send line parser state machine */
  2760. #define        LOOK_FOR_USER        2
  2761. #define        IN_USER            3
  2762. #define        AFTER_USER        4
  2763. #define        LOOK_FOR_HOST        5
  2764. #define        IN_HOST            6
  2765. #define        AFTER_HOST        7
  2766. #define        LOOK_FOR_FROM        8
  2767. #define        IN_FROM            9
  2768. #define        AFTER_FROM        10
  2769. #define        LOOK_FOR_MSGID        11
  2770. #define        IN_MSGID        12
  2771. #define        FINAL_STATE        13
  2772. #define        ERROR_STATE        14
  2773.  
  2774. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  2775.  * return 0
  2776.  */
  2777. static int
  2778. mbx_to(argc,argv,p)
  2779. int argc;
  2780. char *argv[];
  2781. void *p;
  2782. {
  2783. register char *cp;
  2784. register struct mbx *m;
  2785. register int state, i;
  2786. char *user, *host, *from, *msgid;
  2787. int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;
  2788.  
  2789.     m = (struct mbx *)p;
  2790.     /* Free anything that might be allocated
  2791.      * since the last call to mbx_to() or mbx_reply()
  2792.      */
  2793.     free(m->to);
  2794.     m->to = NULLCHAR;
  2795.     free(m->tofrom);
  2796.     m->tofrom = NULLCHAR;
  2797.     free(m->tomsgid);
  2798.     m->tomsgid = NULLCHAR;
  2799.     free(m->origto);
  2800.     m->origto = NULLCHAR;
  2801.     free(m->origbbs);
  2802.     m->origbbs = NULLCHAR;
  2803.     free(m->subject);
  2804.     m->subject = NULLCHAR;
  2805.     free(m->date);
  2806.     m->date = NULLCHAR;
  2807.  
  2808.     if(argc == 1)
  2809.         return -1;
  2810.     i = 1;
  2811.     cp = argv[i];
  2812.     state = LOOK_FOR_USER;
  2813.     while(state < FINAL_STATE){
  2814. #ifdef MBDEBUG
  2815.         tprintf("State is %d, char is %c\n", state, *cp);
  2816. #endif
  2817.         switch(state){
  2818.         case LOOK_FOR_USER:
  2819.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2820.                 state = ERROR_STATE;        /* no user */
  2821.             } else {
  2822.                 user = cp;            /* point at start */
  2823.                 userlen++;            /* start counting */
  2824.                 state = IN_USER;
  2825.             }
  2826.             break;
  2827.         case IN_USER:
  2828.             switch(*cp){
  2829.             case '\0':
  2830.                 state = AFTER_USER;        /* done with username */
  2831.                 break;
  2832.             case '@':
  2833.                 state = LOOK_FOR_HOST;        /* hostname should follow */
  2834.                 break;
  2835.             case '<':
  2836.                 state = LOOK_FOR_FROM;        /* from name should follow */
  2837.                 break;
  2838.             case '$':
  2839.                 state = LOOK_FOR_MSGID;    /* message id should follow */
  2840.                 break;
  2841.             default:
  2842.                 userlen++;            /* part of username */
  2843.             }
  2844.             break;
  2845.         case AFTER_USER:
  2846.             switch(*cp){
  2847.             case '@':
  2848.                 state = LOOK_FOR_HOST;        /* hostname follows */
  2849.                 break;
  2850.             case '<':
  2851.                 state = LOOK_FOR_FROM;        /* fromname follows */
  2852.                 break;
  2853.             case '$':
  2854.             state = LOOK_FOR_MSGID;    /* message id follows */
  2855.                 break;
  2856.             default:
  2857.                 state = ERROR_STATE;
  2858.             }
  2859.             break;
  2860.         case LOOK_FOR_HOST:
  2861.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2862.                 state = ERROR_STATE;
  2863.                 break;
  2864.             }
  2865.             if(*cp == '\0')
  2866.                 break;
  2867.             host = cp;
  2868.             hostlen++;
  2869.             state = IN_HOST;
  2870.             break;
  2871.         case IN_HOST:
  2872.             switch(*cp){
  2873.             case '\0':
  2874.                 state = AFTER_HOST;        /* found user@host */
  2875.                 break;
  2876.             case '@':
  2877.                 state = ERROR_STATE;        /* user@host@? */
  2878.                 break;
  2879.             case '<':
  2880.                 state = LOOK_FOR_FROM;        /* fromname follows */
  2881.                 break;
  2882.             case '$':
  2883.                 state = LOOK_FOR_MSGID;    /* message id follows */
  2884.                 break;
  2885.             default:
  2886.                 hostlen++;
  2887.             }
  2888.             break;
  2889.         case AFTER_HOST:
  2890.             switch(*cp){
  2891.             case '@':
  2892.                 state = ERROR_STATE;        /* user@host @ */
  2893.                 break;
  2894.             case '<':
  2895.                 state = LOOK_FOR_FROM;        /* user@host < */
  2896.                 break;
  2897.             case '$':
  2898.                 state = LOOK_FOR_MSGID;    /* user@host $ */
  2899.                 break;
  2900.             default:
  2901.                 state = ERROR_STATE;        /* user@host foo */
  2902.             }
  2903.             break;
  2904.         case LOOK_FOR_FROM:
  2905.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2906.                 state = ERROR_STATE;
  2907.                 break;
  2908.             }
  2909.             if(*cp == '\0')
  2910.                 break;
  2911.             from = cp;
  2912.             fromlen++;
  2913.             state = IN_FROM;
  2914.             break;
  2915.         case IN_FROM:
  2916.             switch(*cp){
  2917.             case '\0':
  2918.                 state = AFTER_FROM;        /* user@host <foo */
  2919.                 break;
  2920.             case '<':
  2921.                 state = ERROR_STATE;        /* user@host <foo< */
  2922.                 break;
  2923.             case '$':
  2924.                 state = LOOK_FOR_MSGID;    /* message id follows */
  2925.                 break;
  2926.             default:
  2927.                 fromlen++;
  2928.             }
  2929.             break;
  2930.         case AFTER_FROM:
  2931.             switch(*cp){
  2932.             case '@':                /* user@host <foo @ */
  2933.             case '<':                /* user@host <foo < */
  2934.                 state = ERROR_STATE;
  2935.                 break;
  2936.             case '$':
  2937.                 state = LOOK_FOR_MSGID;    /* user@host <foo $ */
  2938.                 break;
  2939.             default:
  2940.                 state = ERROR_STATE;        /* user@host foo */
  2941.             }
  2942.             break;
  2943.         case LOOK_FOR_MSGID:
  2944.             if(*cp == '\0')
  2945.                 break;
  2946.             msgid = cp;
  2947.             msgidlen++;
  2948.             state = IN_MSGID;
  2949.             break;
  2950.         case IN_MSGID:
  2951.             if(*cp == '\0')
  2952.                 state = FINAL_STATE;
  2953.             else
  2954.                 msgidlen++;
  2955.             break;
  2956.         default:
  2957.             /* what are we doing in this state? */
  2958.             state = ERROR_STATE;
  2959.         }
  2960.         if(*(cp) == '\0'){
  2961.             ++i;
  2962.             if(i < argc)
  2963.             cp = argv[i];
  2964.             else break;
  2965.         } else
  2966.             ++cp;
  2967.     }
  2968.     if(state == ERROR_STATE || state == LOOK_FOR_HOST
  2969.      || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
  2970.         return -1;        /* syntax error */
  2971.  
  2972.     m->to = mallocw(userlen + hostlen + 2);
  2973.  
  2974.     strncpy(m->to, user, userlen);
  2975.     m->to[userlen] = '\0';
  2976.  
  2977.     if(hostlen){
  2978.         m->to[userlen] = '@';
  2979.         strncpy(m->to + userlen + 1, host, hostlen);
  2980.         m->to[userlen + hostlen + 1] = '\0';
  2981.     }
  2982.     if(fromlen){
  2983.         m->tofrom = mallocw(fromlen + 1);
  2984.         strncpy(m->tofrom, from, fromlen);
  2985.         m->tofrom[fromlen] = '\0';
  2986.     }
  2987.     if(msgidlen){
  2988.         m->tomsgid = mallocw(msgidlen + 1);
  2989.         strncpy(m->tomsgid, msgid, msgidlen);
  2990.         m->tomsgid[msgidlen] = '\0';
  2991.     }
  2992.     return 0;
  2993. }
  2994.  
  2995. /* This opens the data file and writes the mail header into it.
  2996.  * Returns 0 if OK, and -1 if not.
  2997.  */
  2998. int
  2999. mbx_data(m,cclist,extra, returnreceipt)
  3000. struct mbx *m;
  3001. struct list *cclist;    /* list of carbon copy recipients */
  3002. char *extra;        /* optional extra header lines */
  3003. int returnreceipt;
  3004. {
  3005. time_t t;
  3006. struct list *ap;
  3007. int cccnt = 0;
  3008. char buf[80];
  3009. char stype, *cp = NULLCHAR;
  3010.     
  3011. #ifdef notdef
  3012.     time(&t);
  3013. /*These 2 lines get added again when the smtp-server handles the mail
  3014.  *not really needed - WG7J
  3015.  */
  3016.     fprintf(m->tfile,Hdrs[RECEIVED]);
  3017.     if(m->tofrom != NULLCHAR)
  3018.         fprintf(m->tfile,"from %s ",m->name);
  3019.     fprintf(m->tfile,"by %s (%s)\n\tid AA%ld ; %s",
  3020.         Hostname, Version, get_msgid(0),ptime(&t));
  3021. #endif
  3022.  
  3023. #ifdef nope
  3024.     if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
  3025.       (m->sid & MBX_SID) !=0))
  3026.           fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],m->stype);
  3027. #else
  3028.     stype = m->stype;
  3029.     if(isspace(stype) || stype == 'R' || stype == 'F')
  3030.         stype = 'P';
  3031.     fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],stype);
  3032. #endif
  3033.  
  3034.     /* If m->date is set, use this one (comes from bbs-forwarded mail) */
  3035.     if(m->date != NULLCHAR)
  3036.         fprintf(m->tfile,"%s%s",Hdrs[DATE],m->date);
  3037.     else {
  3038.         time(&t);
  3039.         fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&t));
  3040.     }
  3041.  
  3042.     /* Bulletin ID, if any */
  3043.     fprintf(m->tfile,Hdrs[MSGID]);
  3044.     if(m->tomsgid)
  3045.         fprintf(m->tfile,"<%s@%s.bbs>\n", m->tomsgid, m->name);
  3046.     else    {
  3047.         lastsentid = get_msgid(1);
  3048.         fprintf(m->tfile,"<%ld@%s>\n",lastsentid, Hostname);
  3049.     }
  3050.  
  3051.     /* From : , could use 'real bbs address', if origbbs is set */
  3052.     fprintf(m->tfile,Hdrs[FROM]);
  3053.     if(m->tofrom) {  /* BBS style '< call' */
  3054.         if(m->origbbs != NULLCHAR)
  3055.             sprintf(buf,"%s@%s\n",m->tofrom,m->origbbs);
  3056.         else
  3057.             sprintf(buf,"%s%%%s@%s\n",m->tofrom, m->name, Hostname);
  3058.     } else {
  3059.         if(m->origbbs != NULLCHAR)
  3060.             sprintf(buf,"%s@%s\n",m->name,m->origbbs);
  3061.         else
  3062.             sprintf(buf,"%s@%s ",m->name,Hostname);
  3063.     }
  3064.  
  3065. #ifdef WPAGES
  3066.     if(m->origbbs != NULLCHAR)
  3067.         wpageAdd (buf, 0, 1);    /* update users file */
  3068. #endif
  3069.     if (!m->tofrom && m->origbbs == NULLCHAR)    {
  3070.             if (strcmp(m->realname, "()"))    {
  3071.                 strcat (buf, m->realname);
  3072.             }
  3073.         strcat (buf, "\n");
  3074.     }
  3075.     fputs (buf, m->tfile);
  3076.     if ((m->origto != NULLCHAR) && ((cp = strchr (m->origto, '(')) != 0))
  3077.         *(cp-1) = 0;
  3078.     fprintf(m->tfile,"%s%s\n",Hdrs[TO],m->origto != NULLCHAR ? m->origto : m->to);
  3079.     if (cp)
  3080.         *(cp-1) = ' ';
  3081.  
  3082.     if (m->change != -1)    {
  3083.         /* Write Cc: line */
  3084.         for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  3085.             if(cccnt == 0){
  3086.                 fprintf(m->tfile,"%s",Hdrs[CC]);
  3087.                 cccnt = 4;
  3088.             }
  3089.             else {
  3090.                    fprintf(m->tfile,", ");
  3091.                    cccnt += 2;
  3092.             }
  3093.             if(cccnt + strlen(ap->val) > 80 - 3) {
  3094.                    fprintf(m->tfile,"\n    ");
  3095.                    cccnt = 4;
  3096.             }
  3097.             fputs(ap->val,m->tfile);
  3098.             cccnt += strlen(ap->val);
  3099.         }
  3100.         if(cccnt)
  3101.             fputc('\n',m->tfile);
  3102.     }
  3103.     fprintf(m->tfile,"%s%s\n",Hdrs[SUBJECT],m->subject);
  3104.  
  3105. #ifdef notdef
  3106.     /*not really needed, the 'From <user%fwdbbs@host>' shows this too!*/
  3107.     /* Also store the 'real smtp from' address */
  3108.     if((m->tofrom != NULLCHAR) && (m->origbbs != NULLCHAR))
  3109.         fprintf(m->tfile,"%s%s%%%s@%s\n",Hdrs[XFROM],m->tofrom,m->name, Hostname);
  3110. #endif
  3111.  
  3112.     if(extra != NULLCHAR)
  3113.         fprintf(m->tfile,extra);
  3114.  
  3115.         /*Finish smtp headers*/
  3116.         fprintf(m->tfile,"\n");
  3117.         if(Smtpheaders && m->origbbs == NULLCHAR)    {    /* RFC headers in data area */
  3118.             char *cp;
  3119.             
  3120.         fprintf(m->tfile,Hdrs[MSGID]);
  3121.         if(m->tomsgid)
  3122.             fprintf(m->tfile,"%s\n", m->tomsgid);
  3123.         else    {
  3124.             strcpy (buf, Hostname);
  3125.             if((cp = strchr(buf,'.')) != NULLCHAR)
  3126.                 *cp = '\0';
  3127.             fprintf(m->tfile,"%ld_%s\n",lastsentid, buf);
  3128.         }
  3129.  
  3130.         /* Add a return receipt line, if requested */
  3131.         if (returnreceipt)    {
  3132.                 pax25(buf,Mycall);
  3133.                     if((cp = strchr(buf,'-')) != NULLCHAR)
  3134.                         *cp = '\0'; /* remove SSID */
  3135.                     strlwr (buf);
  3136.             fprintf(m->tfile, "%s%s@%s", Hdrs[RRECEIPT],m->name,buf);
  3137.         
  3138.             sprintf(buf,"%s%s ", (Mbhaddress != NULLCHAR) ? "." : "",
  3139.                 (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
  3140.             strlwr (buf);
  3141.             if (strcmp(m->realname, "()"))
  3142.                         strcat (buf, m->realname);
  3143.                 strcat (buf, "\n");
  3144.             fputs (buf, m->tfile);
  3145.         }
  3146.  
  3147.         if (isgroup (m->to))
  3148.             fprintf (m->tfile, "%s%s@%s\n",  Hdrs[XMAILGROUP], m->to, Hostname);
  3149.  
  3150.             pax25(buf,Mycall);
  3151.                 if((cp = strchr(buf,'-')) != NULLCHAR)
  3152.                     *cp = '\0'; /* remove SSID */
  3153.                 strlwr (buf);
  3154.         fprintf(m->tfile,"%s%s@%s", Hdrs[FROM], m->name, buf);
  3155.         
  3156.         sprintf(buf,"%s%s ", (Mbhaddress != NULLCHAR) ? "." : "",
  3157.             (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
  3158.         strlwr (buf);
  3159.         if (strcmp(m->realname, "()"))
  3160.                     strcat (buf, m->realname);
  3161.             strcat (buf, "\n");
  3162.         fputs (buf, m->tfile);
  3163.         
  3164.         cp = (m->origto != NULLCHAR) ? m->origto : m->to;
  3165.         fprintf(m->tfile,"%s%s",Hdrs[TO],cp);
  3166.         if ((cp = mblookname (NULLMBX, cp)) != 0)    {
  3167.             fputs (cp, m->tfile);
  3168.             free (cp);
  3169.         }
  3170.         fputs("\n\n", m->tfile);
  3171.     }
  3172.     return 0;
  3173. }
  3174.  
  3175.  
  3176. /* Attempt to determine if this is third-party mail. */
  3177. static int 
  3178. thirdparty(m)
  3179. struct mbx *m;
  3180. {
  3181. char buf[MBXLINE], *cp, *rp;
  3182. FILE *fp;
  3183.  
  3184.     if(strpbrk(m->to,"@%!") != NULLCHAR)
  3185.         return 0;
  3186.  
  3187.     rp = strdup(Hostname);
  3188.  
  3189.     if((cp = strchr(rp, '.')) != NULLCHAR)
  3190.         *cp = '\0';
  3191.  
  3192.     if(stricmp(m->to,rp) == 0){
  3193.         free(rp);
  3194.         return -1;
  3195.     }
  3196.     free(rp);
  3197.  
  3198.     if(stricmp(m->to,"sysop") == 0)
  3199.         return -1;
  3200.  
  3201.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  3202.         return 0;
  3203.  
  3204.     while(fgets(buf,MBXLINE,fp) != NULLCHAR){
  3205.         /* The first word on each line is all that matters */
  3206.         if((cp = strpbrk(buf, " \t")) != NULLCHAR)
  3207.             *cp = '\0';
  3208.         if(stricmp(m->to,buf) == 0){
  3209.             fclose(fp);
  3210.             return -1;
  3211.         }
  3212.     }
  3213.     fclose(fp);
  3214.     return 0;
  3215. }
  3216.  
  3217. #ifdef NETROM
  3218. extern struct nrroute_tab *find_nrboth __ARGS((char *alias,char *call));
  3219. #endif
  3220.  
  3221. static int
  3222. dombconnect(argc,argv,p)
  3223. int argc;
  3224. char *argv[];
  3225. void *p;
  3226. {
  3227. struct mbx *m;
  3228. struct nrroute_tab *np;
  3229. int ndigis,i,s;
  3230. struct sockaddr_nr lsocket,fsocket;
  3231. struct sockaddr_ax alsocket;    /*the local socket*/
  3232. struct sockaddr_ax afsocket;    /*the remote socket*/
  3233. struct iface *ifp;
  3234. char alias[AXBUF];
  3235. char local_call[AXALEN];
  3236. char digis[MAXDIGIS][AXALEN];
  3237. char target[AXALEN];
  3238. struct session *sp;
  3239.  
  3240.     m = (struct mbx *) p;
  3241.  
  3242.     if(argc == 1){
  3243. #ifdef  CONVERS
  3244.         if(!Mbconverse) {
  3245.             tputs("Conference server not enabled\n");
  3246.             return 0;
  3247.         }
  3248.         if(m->privs & NO_CONVERS) {
  3249.             tputs(Noperm);
  3250.         mail_error("%s: converse denied\n",m->name);
  3251.             return 0;
  3252.         }
  3253. #ifdef GWTRACE
  3254.         log(m->user,"MBOX CONFERENCE: %s",m->name);
  3255. #endif
  3256.         m->state = MBX_CONVERS;
  3257.     usflush(Curproc->output);
  3258.     if (Current->type == 1)
  3259.         tprintf ("%c%c", IAC, CLEARSCREEN);    /* sets Current->split */
  3260.     sp = Current;
  3261.     pwait (NULL);
  3262.         mbox_converse(m->user, m->name, (int) -1, m);
  3263.         if (sp->split)    {
  3264.         usflush(Curproc->output);
  3265.         tprintf ("%c%c", IAC, CLEARSPLIT);    /* clears Current->split */
  3266.         usflush(Curproc->output);
  3267.             sp->split = 0;
  3268.     }
  3269. #else
  3270.         dombconnecthelp();
  3271. #endif
  3272.         return 0;
  3273.     }
  3274.  
  3275.     if(MBSecure)
  3276. #ifdef NETROM
  3277.         if((m->family != AF_AX25) && (m->family != AF_NETROM)) {
  3278. #else
  3279.         if(m->family != AF_AX25) {
  3280. #endif
  3281.             tputs(Noperm);
  3282.         mail_error("%s: gateway denied (secure mode): %s\n",m->name,cmd_line(argc,argv,m->stype));
  3283.             return 0;
  3284.         }
  3285.  
  3286.     if (argc == 2) {
  3287. #ifndef NETROM
  3288.         dombconnecthelp();
  3289.         return 0;
  3290.     }
  3291. #else
  3292.         /*NETROM connection wanted*/
  3293.         if(!(m->privs & NETROM_CMD)) {
  3294.             tputs(Noperm);
  3295.         mail_error("%s: NETROM gate to %s denied\n",m->name,argv[1]);
  3296.             return 0;
  3297.         }
  3298.  
  3299.         if(Nr_iface == NULLIF){
  3300.             tputs("NET/ROM not activated.\n\n");
  3301.             return 0;
  3302.         }
  3303.         /* See if the requested destination is a known alias or call,
  3304.          * use it if it is.  Otherwize give an error message.
  3305.          */
  3306.         putalias(alias,argv[1],0);
  3307.         strupr(argv[1]);    /*make sure it's upper case*/
  3308.         if((np = find_nrboth(alias,argv[1])) == NULLNRRTAB){
  3309.             /*no such call or node alias*/
  3310.             tputs("no such node\n\n");
  3311.             dombconnecthelp();
  3312.             dombports(0,NULL,NULL);
  3313.             return 0;
  3314.         }
  3315.  
  3316.         if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  3317.             tputs(Nosock);
  3318.             return 0;
  3319.         }
  3320. #ifdef GWTRACE
  3321.         log(m->user,"MBOX NETROM: %s to %s",m->name,argv[1]);
  3322. #endif
  3323.         lsocket.nr_family = AF_NETROM;
  3324.  
  3325.         /* Set up our local username, bind would use Mycall instead */
  3326.         memcpy(lsocket.nr_addr.user,m->call,AXALEN);
  3327.         /* Set up our source address */
  3328.         memcpy(lsocket.nr_addr.node,Nr_iface->hwaddr,AXALEN);
  3329.  
  3330.         bind(s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  3331.  
  3332.         memcpy(fsocket.nr_addr.user,np->call,AXALEN);
  3333.         memcpy(fsocket.nr_addr.node,np->call,AXALEN);
  3334.         fsocket.nr_family = AF_NETROM;
  3335.         m->state = MBX_GATEWAY;
  3336.         return gw_connect(m,s,(struct sockaddr *)&fsocket, sizeof(struct sockaddr_nr));
  3337.     }
  3338. #endif /*NETROM*/
  3339.  
  3340. #ifdef AX25
  3341.     if(argc > 2) {
  3342.         /*AX25 gateway connection wanted*/
  3343.         if(!(m->privs & AX25_CMD)) {
  3344.             tputs(Noperm);
  3345.         mail_error("%s: AX.25 gate to %s on %s denied\n",m->name,argv[2],argv[1]);
  3346.             return 0;
  3347.         }
  3348.  
  3349.         if( ((ifp = if_lookup(argv[1])) == NULLIF) ||
  3350.            ((ifp->flags & HIDE_PORT) && !(m->privs & SYSOP_CMD)) ||
  3351.             (ifp->type != CL_AX25) ) {
  3352.             tprintf("Unknown port %s\n",argv[1]);
  3353.             dombports(0,NULL,NULL);
  3354.             return 0;
  3355.         }
  3356.         if(ifp->type != CL_AX25){
  3357.             tprintf("Port %s not usable for AX.25 connects\n",argv[1]);
  3358.             dombports(0,NULL,NULL);
  3359.             return 0;
  3360.         }
  3361.         if(setcall(target,argv[2]) == -1){
  3362.             tprintf("Bad call %s\n",argv[2]);
  3363.             return 0;
  3364.         }
  3365.         /* If digipeaters are given, put them in the routing table */
  3366.         if(argc > 3){
  3367.             ndigis = argc - 3;
  3368.             if(ndigis > MAXDIGIS){
  3369.                 tputs("Too many digipeaters\n");
  3370.                 return 0;
  3371.             }
  3372.             for(i=0;i<ndigis;i++){
  3373.                 if(setcall(digis[i],argv[i+3]) == -1){
  3374.                     tprintf("Bad digipeater %s\n",argv[i+3]);
  3375.                     return 0;
  3376.                 }
  3377.             }
  3378.             if(ax_add(target,AX_AUTO,digis,ndigis,ifp) == NULLAXR){
  3379.                 tputs("AX25 route add failed\n");
  3380.                 return 0;
  3381.             }
  3382.         }
  3383.         if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  3384.             tputs(Nosock);
  3385.             return 0;
  3386.         }
  3387. #ifdef GWTRACE
  3388.         log(m->user,"MBOX AX25: %s to %s on %s",m->name,argv[2],argv[1]);
  3389. #endif
  3390.  
  3391.         /*fill in the known stuff*/
  3392.         alsocket.sax_family = afsocket.sax_family= AF_AX25;
  3393.         
  3394.         /*the remote call to connect to*/
  3395.         setcall(afsocket.ax25_addr,argv[2]);
  3396.  
  3397.         /*the outgoing interface*/
  3398.         strncpy(afsocket.iface,argv[1],ILEN);
  3399.  
  3400.         /*now set local user call, invert ssid*/
  3401.         memcpy(local_call,m->call,AXALEN);
  3402.         local_call[AXALEN-1] ^= 0x1e;
  3403.         memcpy(alsocket.ax25_addr,local_call,AXALEN);
  3404.         /*and bind it (otherwize Mycall will be used!)*/
  3405.         bind(s,(char *)&alsocket,sizeof(struct sockaddr_ax));
  3406.         m->state = MBX_GATEWAY;
  3407.         return gw_connect(m,s,(struct sockaddr *)&afsocket, sizeof(struct sockaddr_ax));
  3408.     }
  3409. #endif /* AX25 */
  3410.  
  3411.     return 0;
  3412. }
  3413.  
  3414. #endif /* MAILBOX */
  3415.  
  3416.